mirror of
https://github.com/MGislv/NekoX.git
synced 2024-07-04 11:13:36 +00:00
merge upstream v7.9.0 & v7.9.1
This commit is contained in:
commit
1cc03ad060
|
@ -3,15 +3,15 @@ import cn.hutool.core.util.RuntimeUtil
|
|||
apply plugin: "com.android.application"
|
||||
apply plugin: "kotlin-android"
|
||||
|
||||
def verName = "7.8.2-preview01"
|
||||
def verCode = 350
|
||||
def verName = "7.9.1-preview01"
|
||||
def verCode = 355
|
||||
|
||||
if (System.getenv("DEBUG_BUILD") == "true") {
|
||||
verName += "-" + RuntimeUtil.execForStr("git log --pretty=format:'%h' -n 1")
|
||||
}
|
||||
|
||||
def officialVer = "7.8.2"
|
||||
def officialCode = 2376
|
||||
def officialVer = "7.9.1"
|
||||
def officialCode = 2387
|
||||
|
||||
def serviceAccountCredentialsFile = rootProject.file("service_account_credentials.json")
|
||||
|
||||
|
|
|
@ -448,7 +448,7 @@ target_compile_definitions(sqlite PUBLIC
|
|||
#voip
|
||||
include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt)
|
||||
|
||||
set(NATIVE_LIB "tmessages.39")
|
||||
set(NATIVE_LIB "tmessages.40")
|
||||
|
||||
#tmessages
|
||||
add_library(${NATIVE_LIB} SHARED
|
||||
|
|
|
@ -213,8 +213,8 @@ void setUserId(JNIEnv *env, jclass c, jint instanceNum, int32_t id) {
|
|||
ConnectionsManager::getInstance(instanceNum).setUserId(id);
|
||||
}
|
||||
|
||||
void switchBackend(JNIEnv *env, jclass c, jint instanceNum) {
|
||||
ConnectionsManager::getInstance(instanceNum).switchBackend();
|
||||
void switchBackend(JNIEnv *env, jclass c, jint instanceNum, jboolean restart) {
|
||||
ConnectionsManager::getInstance(instanceNum).switchBackend(restart);
|
||||
}
|
||||
|
||||
void pauseNetwork(JNIEnv *env, jclass c, jint instanceNum) {
|
||||
|
@ -528,7 +528,7 @@ static JNINativeMethod ConnectionsManagerMethods[] = {
|
|||
{"native_setLangCode", "(ILjava/lang/String;)V", (void *) setLangCode},
|
||||
{"native_setRegId", "(ILjava/lang/String;)V", (void *) setRegId},
|
||||
{"native_setSystemLangCode", "(ILjava/lang/String;)V", (void *) setSystemLangCode},
|
||||
{"native_switchBackend", "(I)V", (void *) switchBackend},
|
||||
{"native_switchBackend", "(IZ)V", (void *) switchBackend},
|
||||
{"native_pauseNetwork", "(I)V", (void *) pauseNetwork},
|
||||
{"native_resumeNetwork", "(IZ)V", (void *) resumeNetwork},
|
||||
{"native_updateDcSettings", "(I)V", (void *) updateDcSettings},
|
||||
|
|
|
@ -1889,14 +1889,16 @@ void ConnectionsManager::setUserId(int32_t userId) {
|
|||
});
|
||||
}
|
||||
|
||||
void ConnectionsManager::switchBackend() {
|
||||
//scheduleTask([&] {
|
||||
currentDatacenterId = 1;
|
||||
testBackend = !testBackend;
|
||||
datacenters.clear();
|
||||
initDatacenters();
|
||||
saveConfig();
|
||||
//exit(1);
|
||||
void ConnectionsManager::switchBackend(bool restart) {
|
||||
//scheduleTask([&, restart] {
|
||||
currentDatacenterId = 1;
|
||||
testBackend = !testBackend;
|
||||
datacenters.clear();
|
||||
initDatacenters();
|
||||
saveConfig();
|
||||
if (restart) {
|
||||
exit(1);
|
||||
}
|
||||
//});
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
void setDelegate(ConnectiosManagerDelegate *connectiosManagerDelegate);
|
||||
ConnectionState getConnectionState();
|
||||
void setUserId(int32_t userId);
|
||||
void switchBackend();
|
||||
void switchBackend(bool restart);
|
||||
void resumeNetwork(bool partial);
|
||||
void pauseNetwork();
|
||||
void setNetworkAvailable(bool value, int32_t type, bool slow);
|
||||
|
|
|
@ -2218,6 +2218,7 @@ add_library(voipandroid STATIC
|
|||
voip/webrtc/modules/audio_device/android/audio_manager.cc
|
||||
voip/webrtc/modules/audio_device/android/audio_record_jni.cc
|
||||
voip/webrtc/modules/audio_device/android/audio_screen_record_jni.cc
|
||||
voip/webrtc/modules/audio_device/android/audio_merged_screen_record_jni.cc
|
||||
voip/webrtc/modules/audio_device/android/audio_track_jni.cc
|
||||
voip/webrtc/modules/audio_device/android/build_info.cc
|
||||
voip/webrtc/modules/audio_device/android/opensles_common.cc
|
||||
|
|
|
@ -169,8 +169,10 @@ struct InstanceHolder {
|
|||
std::unique_ptr<Instance> nativeInstance;
|
||||
std::unique_ptr<GroupInstanceCustomImpl> groupNativeInstance;
|
||||
std::shared_ptr<tgcalls::VideoCaptureInterface> _videoCapture;
|
||||
std::shared_ptr<tgcalls::VideoCaptureInterface> _screenVideoCapture;
|
||||
std::shared_ptr<PlatformContext> _platformContext;
|
||||
std::map<std::string, SetVideoSink> remoteGroupSinks;
|
||||
bool useScreencast = false;
|
||||
};
|
||||
|
||||
jlong getInstanceHolderId(JNIEnv *env, jobject obj) {
|
||||
|
@ -392,38 +394,40 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGrou
|
|||
});
|
||||
},
|
||||
.videoCapture = videoCapture,
|
||||
.requestBroadcastPart = [](std::shared_ptr<PlatformContext> platformContext, int64_t timestamp, int64_t duration, std::function<void(BroadcastPart &&)> callback) -> std::shared_ptr<BroadcastPartTask> {
|
||||
std::shared_ptr<BroadcastPartTask> task = std::make_shared<BroadcastPartTaskJava>(platformContext, callback, timestamp);
|
||||
((AndroidContext *) platformContext.get())->streamTask = task;
|
||||
tgvoip::jni::DoWithJNI([platformContext, timestamp, duration, task](JNIEnv *env) {
|
||||
jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onRequestBroadcastPart", "(JJ)V"), timestamp, duration);
|
||||
});
|
||||
return task;
|
||||
},
|
||||
.videoContentType = screencast ? VideoContentType::Screencast : VideoContentType::Generic,
|
||||
.initialEnableNoiseSuppression = (bool) noiseSupression,
|
||||
.requestMediaChannelDescriptions = [platformContext](std::vector<uint32_t> const &ssrcs, std::function<void(std::vector<MediaChannelDescription> &&)> callback) -> std::shared_ptr<RequestMediaChannelDescriptionTask> {
|
||||
std::shared_ptr<RequestMediaChannelDescriptionTaskJava> task = std::make_shared<RequestMediaChannelDescriptionTaskJava>(platformContext, callback);
|
||||
((AndroidContext *) platformContext.get())->descriptionTasks.push_back(task);
|
||||
tgvoip::jni::DoWithJNI([platformContext, ssrcs, task](JNIEnv *env) {
|
||||
unsigned int size = ssrcs.size();
|
||||
jintArray intArray = env->NewIntArray(size);
|
||||
|
||||
jint intFill[size];
|
||||
for (int a = 0; a < size; a++) {
|
||||
intFill[a] = ssrcs[a];
|
||||
}
|
||||
env->SetIntArrayRegion(intArray, 0, size, intFill);
|
||||
|
||||
jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onParticipantDescriptionsRequired", "(J[I)V"), (jlong) task.get(), intArray);
|
||||
env->DeleteLocalRef(intArray);
|
||||
});
|
||||
return task;
|
||||
},
|
||||
.platformContext = platformContext
|
||||
};
|
||||
if (!screencast) {
|
||||
descriptor.requestBroadcastPart = [](std::shared_ptr<PlatformContext> platformContext, int64_t timestamp, int64_t duration, std::function<void(BroadcastPart &&)> callback) -> std::shared_ptr<BroadcastPartTask> {
|
||||
std::shared_ptr<BroadcastPartTask> task = std::make_shared<BroadcastPartTaskJava>(platformContext, callback, timestamp);
|
||||
((AndroidContext *) platformContext.get())->streamTask = task;
|
||||
tgvoip::jni::DoWithJNI([platformContext, timestamp, duration, task](JNIEnv *env) {
|
||||
jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onRequestBroadcastPart", "(JJ)V"), timestamp, duration);
|
||||
});
|
||||
return task;
|
||||
};
|
||||
descriptor.requestMediaChannelDescriptions = [platformContext](std::vector<uint32_t> const &ssrcs, std::function<void(std::vector<MediaChannelDescription> &&)> callback) -> std::shared_ptr<RequestMediaChannelDescriptionTask> {
|
||||
std::shared_ptr<RequestMediaChannelDescriptionTaskJava> task = std::make_shared<RequestMediaChannelDescriptionTaskJava>(platformContext, callback);
|
||||
((AndroidContext *) platformContext.get())->descriptionTasks.push_back(task);
|
||||
tgvoip::jni::DoWithJNI([platformContext, ssrcs, task](JNIEnv *env) {
|
||||
unsigned int size = ssrcs.size();
|
||||
jintArray intArray = env->NewIntArray(size);
|
||||
|
||||
jint intFill[size];
|
||||
for (int a = 0; a < size; a++) {
|
||||
intFill[a] = ssrcs[a];
|
||||
}
|
||||
env->SetIntArrayRegion(intArray, 0, size, intFill);
|
||||
|
||||
jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onParticipantDescriptionsRequired", "(J[I)V"), (jlong) task.get(), intArray);
|
||||
env->DeleteLocalRef(intArray);
|
||||
});
|
||||
return task;
|
||||
};
|
||||
}
|
||||
|
||||
auto *holder = new InstanceHolder;
|
||||
holder->groupNativeInstance = std::make_unique<GroupInstanceCustomImpl>(std::move(descriptor));
|
||||
|
@ -846,9 +850,9 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_createVi
|
|||
initWebRTC(env);
|
||||
std::unique_ptr<VideoCaptureInterface> capture;
|
||||
if (type == 0 || type == 1) {
|
||||
capture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), type == 1 ? "front" : "back", std::make_shared<AndroidContext>(env, nullptr, false));
|
||||
capture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), type == 1 ? "front" : "back", false, std::make_shared<AndroidContext>(env, nullptr, false));
|
||||
} else {
|
||||
capture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), "screen", std::make_shared<AndroidContext>(env, nullptr, true));
|
||||
capture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), "screen", true, std::make_shared<AndroidContext>(env, nullptr, true));
|
||||
}
|
||||
capture->setOutput(webrtc::JavaToNativeVideoSink(env, localSink));
|
||||
capture->setState(VideoState::Active);
|
||||
|
@ -866,6 +870,15 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_activateV
|
|||
capturer->setState(VideoState::Active);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_clearVideoCapturer(JNIEnv *env, jobject obj) {
|
||||
InstanceHolder *instance = getInstanceHolder(env, obj);
|
||||
if (instance->nativeInstance) {
|
||||
instance->nativeInstance->setVideoCapture(nullptr);
|
||||
} else if (instance->groupNativeInstance) {
|
||||
instance->groupNativeInstance->setVideoSource(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_destroyVideoCapturer(JNIEnv *env, jclass clazz, jlong videoCapturer) {
|
||||
auto capturer = reinterpret_cast<VideoCaptureInterface *>(videoCapturer);
|
||||
delete capturer;
|
||||
|
@ -899,24 +912,35 @@ JNIEXPORT jboolean JNICALL Java_org_telegram_messenger_voip_NativeInstance_hasVi
|
|||
|
||||
JNIEXPORT void Java_org_telegram_messenger_voip_NativeInstance_setVideoState(JNIEnv *env, jobject obj, jint state) {
|
||||
InstanceHolder *instance = getInstanceHolder(env, obj);
|
||||
if (instance->_videoCapture == nullptr) {
|
||||
std::shared_ptr<tgcalls::VideoCaptureInterface> capturer = instance->useScreencast ? instance->_screenVideoCapture : instance->_videoCapture;
|
||||
if (capturer == nullptr) {
|
||||
return;
|
||||
}
|
||||
instance->_videoCapture->setState(static_cast<VideoState>(state));
|
||||
capturer->setState(static_cast<VideoState>(state));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setupOutgoingVideo(JNIEnv *env, jobject obj, jobject localSink, jboolean front) {
|
||||
JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setupOutgoingVideo(JNIEnv *env, jobject obj, jobject localSink, jint type) {
|
||||
InstanceHolder *instance = getInstanceHolder(env, obj);
|
||||
if (instance->_videoCapture) {
|
||||
return;
|
||||
std::shared_ptr<tgcalls::VideoCaptureInterface> capturer;
|
||||
if (type == 0 || type == 1) {
|
||||
if (instance->_videoCapture == nullptr) {
|
||||
instance->_videoCapture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), type == 1 ? "front" : "back", false, instance->_platformContext);
|
||||
}
|
||||
capturer = instance->_videoCapture;
|
||||
instance->useScreencast = false;
|
||||
} else {
|
||||
if (instance->_screenVideoCapture == nullptr) {
|
||||
instance->_screenVideoCapture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), "screen", true, instance->_platformContext);
|
||||
}
|
||||
capturer = instance->_screenVideoCapture;
|
||||
instance->useScreencast = true;
|
||||
}
|
||||
instance->_videoCapture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), front ? "front" : "back", instance->_platformContext);
|
||||
instance->_videoCapture->setOutput(webrtc::JavaToNativeVideoSink(env, localSink));
|
||||
instance->_videoCapture->setState(VideoState::Active);
|
||||
capturer->setOutput(webrtc::JavaToNativeVideoSink(env, localSink));
|
||||
capturer->setState(VideoState::Active);
|
||||
if (instance->nativeInstance) {
|
||||
instance->nativeInstance->setVideoCapture(instance->_videoCapture);
|
||||
instance->nativeInstance->setVideoCapture(capturer);
|
||||
} else if (instance->groupNativeInstance) {
|
||||
instance->groupNativeInstance->setVideoCapture(instance->_videoCapture);
|
||||
instance->groupNativeInstance->setVideoCapture(capturer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -931,6 +955,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setupOutg
|
|||
instance->_videoCapture->setState(VideoState::Active);
|
||||
if (instance->nativeInstance) {
|
||||
instance->nativeInstance->setVideoCapture(instance->_videoCapture);
|
||||
instance->useScreencast = false;
|
||||
} else if (instance->groupNativeInstance) {
|
||||
instance->groupNativeInstance->setVideoCapture(instance->_videoCapture);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ bool SkipDefaultDevice(const char *name) {
|
|||
} // namespace
|
||||
|
||||
void SetAudioInputDeviceById(webrtc::AudioDeviceModule *adm, const std::string &id) {
|
||||
const auto recording = adm->Recording();
|
||||
const auto recording = adm->Recording() || adm->RecordingIsInitialized();
|
||||
if (recording) {
|
||||
adm->StopRecording();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace webrtc {
|
||||
class VideoTrackSourceInterface;
|
||||
|
|
|
@ -191,6 +191,8 @@ public:
|
|||
virtual void setInputVolume(float level) = 0;
|
||||
virtual void setOutputVolume(float level) = 0;
|
||||
virtual void setAudioOutputDuckingEnabled(bool enabled) = 0;
|
||||
virtual void addExternalAudioSamples(std::vector<uint8_t> &&samples) {
|
||||
}
|
||||
|
||||
virtual void setIsLowBatteryLevel(bool isLowBatteryLevel) = 0;
|
||||
|
||||
|
|
|
@ -126,6 +126,12 @@ void InstanceImpl::setAudioOutputDuckingEnabled(bool enabled) {
|
|||
// TODO: not implemented
|
||||
}
|
||||
|
||||
void InstanceImpl::addExternalAudioSamples(std::vector<uint8_t> &&samples) {
|
||||
_manager->perform(RTC_FROM_HERE, [samples = std::move(samples)](Manager *manager) mutable {
|
||||
manager->addExternalAudioSamples(std::move(samples));
|
||||
});
|
||||
}
|
||||
|
||||
void InstanceImpl::setIsLowBatteryLevel(bool isLowBatteryLevel) {
|
||||
_manager->perform(RTC_FROM_HERE, [isLowBatteryLevel](Manager *manager) {
|
||||
manager->setIsLowBatteryLevel(isLowBatteryLevel);
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
void setInputVolume(float level) override;
|
||||
void setOutputVolume(float level) override;
|
||||
void setAudioOutputDuckingEnabled(bool enabled) override;
|
||||
void addExternalAudioSamples(std::vector<uint8_t> &&samples) override;
|
||||
void setIsLowBatteryLevel(bool isLowBatteryLevel) override;
|
||||
std::string getLastError() override;
|
||||
std::string getDebugInfo() override;
|
||||
|
|
|
@ -453,4 +453,10 @@ void Manager::setOutputVolume(float level) {
|
|||
});
|
||||
}
|
||||
|
||||
void Manager::addExternalAudioSamples(std::vector<uint8_t> &&samples) {
|
||||
_mediaManager->perform(RTC_FROM_HERE, [samples = std::move(samples)](MediaManager *mediaManager) mutable {
|
||||
mediaManager->addExternalAudioSamples(std::move(samples));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace tgcalls
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
void setInputVolume(float level);
|
||||
void setOutputVolume(float level);
|
||||
|
||||
void addExternalAudioSamples(std::vector<uint8_t> &&samples);
|
||||
|
||||
private:
|
||||
void sendSignalingAsync(int delayMs, int cause);
|
||||
void receiveMessage(DecryptedMessage &&message);
|
||||
|
|
|
@ -66,6 +66,90 @@ public:
|
|||
virtual ~AudioCaptureAnalyzer() = default;
|
||||
};
|
||||
|
||||
class AudioCapturePostProcessor : public webrtc::CustomProcessing {
|
||||
public:
|
||||
AudioCapturePostProcessor(std::function<void(float)> updated, std::vector<float> *externalAudioSamples, webrtc::Mutex *externalAudioSamplesMutex) :
|
||||
_updated(updated),
|
||||
_externalAudioSamples(externalAudioSamples),
|
||||
_externalAudioSamplesMutex(externalAudioSamplesMutex) {
|
||||
}
|
||||
|
||||
virtual ~AudioCapturePostProcessor() {
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void Initialize(int sample_rate_hz, int num_channels) override {
|
||||
}
|
||||
|
||||
virtual void Process(webrtc::AudioBuffer *buffer) override {
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
if (buffer->num_channels() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
float peak = 0;
|
||||
int peakCount = 0;
|
||||
const float *samples = buffer->channels_const()[0];
|
||||
for (int i = 0; i < buffer->num_frames(); i++) {
|
||||
float sample = samples[i];
|
||||
if (sample < 0) {
|
||||
sample = -sample;
|
||||
}
|
||||
if (peak < sample) {
|
||||
peak = sample;
|
||||
}
|
||||
peakCount += 1;
|
||||
}
|
||||
|
||||
_peakCount += peakCount;
|
||||
if (_peak < peak) {
|
||||
_peak = peak;
|
||||
}
|
||||
if (_peakCount >= 1200) {
|
||||
float level = _peak / 8000.0f;
|
||||
_peak = 0;
|
||||
_peakCount = 0;
|
||||
|
||||
_updated(level);
|
||||
}
|
||||
|
||||
_externalAudioSamplesMutex->Lock();
|
||||
if (!_externalAudioSamples->empty()) {
|
||||
float *bufferData = buffer->channels()[0];
|
||||
int takenSamples = 0;
|
||||
for (int i = 0; i < _externalAudioSamples->size() && i < buffer->num_frames(); i++) {
|
||||
float sample = (*_externalAudioSamples)[i];
|
||||
sample += bufferData[i];
|
||||
sample = std::min(sample, 32768.f);
|
||||
sample = std::max(sample, -32768.f);
|
||||
bufferData[i] = sample;
|
||||
takenSamples++;
|
||||
}
|
||||
if (takenSamples != 0) {
|
||||
_externalAudioSamples->erase(_externalAudioSamples->begin(), _externalAudioSamples->begin() + takenSamples);
|
||||
}
|
||||
}
|
||||
_externalAudioSamplesMutex->Unlock();
|
||||
}
|
||||
|
||||
virtual std::string ToString() const override {
|
||||
return "CustomPostProcessing";
|
||||
}
|
||||
|
||||
virtual void SetRuntimeSetting(webrtc::AudioProcessing::RuntimeSetting setting) override {
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(float)> _updated;
|
||||
|
||||
int32_t _peakCount = 0;
|
||||
float _peak = 0;
|
||||
|
||||
std::vector<float> *_externalAudioSamples = nullptr;
|
||||
webrtc::Mutex *_externalAudioSamplesMutex = nullptr;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -226,55 +310,21 @@ _platformContext(platformContext) {
|
|||
preferredCodecs,
|
||||
_platformContext);
|
||||
|
||||
// [this] should outlive the analyzer
|
||||
auto analyzer = new AudioCaptureAnalyzer([this](const webrtc::AudioBuffer* buffer) {
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
if (buffer->num_channels() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
float peak = 0;
|
||||
int peakCount = 0;
|
||||
const float *samples = buffer->channels_const()[0];
|
||||
for (int i = 0; i < buffer->num_frames(); i++) {
|
||||
float sample = samples[i];
|
||||
if (sample < 0) {
|
||||
sample = -sample;
|
||||
}
|
||||
if (peak < sample) {
|
||||
peak = sample;
|
||||
}
|
||||
peakCount += 1;
|
||||
}
|
||||
|
||||
this->_thread->PostTask(RTC_FROM_HERE, [this, peak, peakCount](){
|
||||
auto strong = this;
|
||||
|
||||
strong->_myAudioLevelPeakCount += peakCount;
|
||||
if (strong->_myAudioLevelPeak < peak) {
|
||||
strong->_myAudioLevelPeak = peak;
|
||||
}
|
||||
if (strong->_myAudioLevelPeakCount >= 1200) {
|
||||
float level = strong->_myAudioLevelPeak / 4000.0f;
|
||||
strong->_myAudioLevelPeak = 0;
|
||||
strong->_myAudioLevelPeakCount = 0;
|
||||
strong->_currentMyAudioLevel = level;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
webrtc::AudioProcessingBuilder builder;
|
||||
builder.SetCaptureAnalyzer(std::unique_ptr<AudioCaptureAnalyzer>(analyzer));
|
||||
|
||||
std::unique_ptr<AudioCapturePostProcessor> audioProcessor = std::make_unique<AudioCapturePostProcessor>([this](float level) {
|
||||
this->_thread->PostTask(RTC_FROM_HERE, [this, level](){
|
||||
auto strong = this;
|
||||
strong->_currentMyAudioLevel = level;
|
||||
});
|
||||
}, &_externalAudioSamples, &_externalAudioSamplesMutex);
|
||||
builder.SetCapturePostProcessing(std::move(audioProcessor));
|
||||
mediaDeps.audio_processing = builder.Create();
|
||||
|
||||
/*_audioDeviceModule = this->createAudioDeviceModule();
|
||||
_audioDeviceModule = this->createAudioDeviceModule();
|
||||
if (!_audioDeviceModule) {
|
||||
return;
|
||||
}
|
||||
mediaDeps.adm = _audioDeviceModule;*/
|
||||
mediaDeps.adm = _audioDeviceModule;
|
||||
|
||||
_mediaEngine = cricket::CreateMediaEngine(std::move(mediaDeps));
|
||||
_mediaEngine->Init();
|
||||
|
@ -367,7 +417,11 @@ rtc::scoped_refptr<webrtc::AudioDeviceModule> MediaManager::createAudioDeviceMod
|
|||
return result;
|
||||
}
|
||||
}
|
||||
#ifdef ANDROID
|
||||
return check(create(webrtc::AudioDeviceModule::kAndroidMergedScreenAudio));
|
||||
#else
|
||||
return check(create(webrtc::AudioDeviceModule::kPlatformDefaultAudio));
|
||||
#endif
|
||||
}
|
||||
|
||||
void MediaManager::start() {
|
||||
|
@ -587,6 +641,7 @@ void MediaManager::setSendVideo(std::shared_ptr<VideoCaptureInterface> videoCapt
|
|||
_videoCapture = videoCapture;
|
||||
if (_videoCapture) {
|
||||
_videoCapture->setPreferredAspectRatio(_preferredAspectRatio);
|
||||
_isScreenCapture = _videoCapture->isScreenCapture();
|
||||
|
||||
const auto thread = _thread;
|
||||
const auto weak = std::weak_ptr<MediaManager>(shared_from_this());
|
||||
|
@ -599,7 +654,10 @@ void MediaManager::setSendVideo(std::shared_ptr<VideoCaptureInterface> videoCapt
|
|||
});
|
||||
setOutgoingVideoState(VideoState::Active);
|
||||
} else {
|
||||
_isScreenCapture = false;
|
||||
|
||||
setOutgoingVideoState(VideoState::Inactive);
|
||||
resetSendingVideo();
|
||||
}
|
||||
|
||||
checkIsSendingVideoChanged(wasSending);
|
||||
|
@ -669,6 +727,30 @@ void MediaManager::configureSendingVideoIfNeeded() {
|
|||
adjustBitratePreferences(true);
|
||||
}
|
||||
|
||||
void MediaManager::resetSendingVideo() {
|
||||
if (!_didConfigureVideo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_enableFlexfec) {
|
||||
_videoChannel->RemoveSendStream(_ssrcVideo.outgoing);
|
||||
_videoChannel->RemoveSendStream(_ssrcVideo.fecOutgoing);
|
||||
} else {
|
||||
_videoChannel->RemoveSendStream(_ssrcVideo.outgoing);
|
||||
}
|
||||
|
||||
if (_enableFlexfec) {
|
||||
cricket::StreamParams videoSendStreamParams;
|
||||
cricket::SsrcGroup videoSendSsrcGroup(cricket::kFecFrSsrcGroupSemantics, {_ssrcVideo.outgoing, _ssrcVideo.fecOutgoing});
|
||||
videoSendStreamParams.ssrcs = {_ssrcVideo.outgoing};
|
||||
videoSendStreamParams.ssrc_groups.push_back(videoSendSsrcGroup);
|
||||
videoSendStreamParams.cname = "cname";
|
||||
_videoChannel->AddSendStream(videoSendStreamParams);
|
||||
} else {
|
||||
_videoChannel->AddSendStream(cricket::StreamParams::CreateLegacy(_ssrcVideo.outgoing));
|
||||
}
|
||||
}
|
||||
|
||||
void MediaManager::checkIsSendingVideoChanged(bool wasSending) {
|
||||
const auto sending = computeIsSendingVideo();
|
||||
if (sending == wasSending) {
|
||||
|
@ -708,9 +790,16 @@ int MediaManager::getMaxAudioBitrate() const {
|
|||
void MediaManager::adjustBitratePreferences(bool resetStartBitrate) {
|
||||
if (computeIsSendingVideo()) {
|
||||
webrtc::BitrateConstraints preferences;
|
||||
preferences.min_bitrate_bps = 64000;
|
||||
if (resetStartBitrate) {
|
||||
preferences.start_bitrate_bps = 400000;
|
||||
if (_isScreenCapture) {
|
||||
preferences.min_bitrate_bps = 700000;
|
||||
if (resetStartBitrate) {
|
||||
preferences.start_bitrate_bps = 700000;
|
||||
}
|
||||
} else {
|
||||
preferences.min_bitrate_bps = 64000;
|
||||
if (resetStartBitrate) {
|
||||
preferences.start_bitrate_bps = 400000;
|
||||
}
|
||||
}
|
||||
preferences.max_bitrate_bps = getMaxVideoBitrate();
|
||||
|
||||
|
@ -927,6 +1016,23 @@ void MediaManager::setOutputVolume(float level) {
|
|||
// }
|
||||
}
|
||||
|
||||
void MediaManager::addExternalAudioSamples(std::vector<uint8_t> &&samples) {
|
||||
if (samples.size() % 2 != 0) {
|
||||
return;
|
||||
}
|
||||
_externalAudioSamplesMutex.Lock();
|
||||
|
||||
size_t previousSize = _externalAudioSamples.size();
|
||||
_externalAudioSamples.resize(_externalAudioSamples.size() + samples.size() / 2);
|
||||
webrtc::S16ToFloatS16((const int16_t *)samples.data(), samples.size() / 2, _externalAudioSamples.data() + previousSize);
|
||||
|
||||
if (_externalAudioSamples.size() > 2 * 48000) {
|
||||
_externalAudioSamples.erase(_externalAudioSamples.begin(), _externalAudioSamples.begin() + (_externalAudioSamples.size() - 2 * 48000));
|
||||
}
|
||||
|
||||
_externalAudioSamplesMutex.Unlock();
|
||||
}
|
||||
|
||||
MediaManager::NetworkInterfaceImpl::NetworkInterfaceImpl(MediaManager *mediaManager, bool isVideo) :
|
||||
_mediaManager(mediaManager),
|
||||
_isVideo(isVideo) {
|
||||
|
|
|
@ -71,6 +71,8 @@ public:
|
|||
void setInputVolume(float level);
|
||||
void setOutputVolume(float level);
|
||||
|
||||
void addExternalAudioSamples(std::vector<uint8_t> &&samples);
|
||||
|
||||
private:
|
||||
struct SSRC {
|
||||
uint32_t incoming = 0;
|
||||
|
@ -100,6 +102,7 @@ private:
|
|||
|
||||
bool computeIsSendingVideo() const;
|
||||
void configureSendingVideoIfNeeded();
|
||||
void resetSendingVideo();
|
||||
void checkIsSendingVideoChanged(bool wasSending);
|
||||
bool videoCodecsNegotiated() const;
|
||||
|
||||
|
@ -156,6 +159,7 @@ private:
|
|||
std::unique_ptr<cricket::VideoMediaChannel> _videoChannel;
|
||||
std::unique_ptr<webrtc::VideoBitrateAllocatorFactory> _videoBitrateAllocatorFactory;
|
||||
std::shared_ptr<VideoCaptureInterface> _videoCapture;
|
||||
bool _isScreenCapture = false;
|
||||
std::shared_ptr<VideoSinkInterfaceProxyImpl> _incomingVideoSinkProxy;
|
||||
|
||||
float _localPreferredVideoAspectRatio = 0.0f;
|
||||
|
@ -166,14 +170,15 @@ private:
|
|||
|
||||
float _currentAudioLevel = 0.0f;
|
||||
float _currentMyAudioLevel = 0.0f;
|
||||
int _myAudioLevelPeakCount = 0;
|
||||
int _myAudioLevelPeak = 0;
|
||||
|
||||
std::unique_ptr<MediaManager::NetworkInterfaceImpl> _audioNetworkInterface;
|
||||
std::unique_ptr<MediaManager::NetworkInterfaceImpl> _videoNetworkInterface;
|
||||
|
||||
std::vector<CallStatsBitrateRecord> _bitrateRecords;
|
||||
|
||||
std::vector<float> _externalAudioSamples;
|
||||
webrtc::Mutex _externalAudioSamplesMutex;
|
||||
|
||||
std::shared_ptr<PlatformContext> _platformContext;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
namespace tgcalls {
|
||||
|
||||
std::unique_ptr<VideoCaptureInterface> VideoCaptureInterface::Create(
|
||||
std::shared_ptr<Threads> threads, std::string deviceId,
|
||||
std::shared_ptr<Threads> threads, std::string deviceId, bool isScreenCapture,
|
||||
std::shared_ptr<PlatformContext> platformContext) {
|
||||
return std::make_unique<VideoCaptureInterfaceImpl>(deviceId, platformContext, std::move(threads));
|
||||
return std::make_unique<VideoCaptureInterfaceImpl>(deviceId, isScreenCapture, platformContext, std::move(threads));
|
||||
}
|
||||
|
||||
VideoCaptureInterface::~VideoCaptureInterface() = default;
|
||||
|
|
|
@ -34,10 +34,12 @@ public:
|
|||
static std::unique_ptr<VideoCaptureInterface> Create(
|
||||
std::shared_ptr<Threads> threads,
|
||||
std::string deviceId = std::string(),
|
||||
bool isScreenCapture = false,
|
||||
std::shared_ptr<PlatformContext> platformContext = nullptr);
|
||||
|
||||
virtual ~VideoCaptureInterface();
|
||||
|
||||
virtual bool isScreenCapture() = 0;
|
||||
virtual void switchToDevice(std::string deviceId) = 0;
|
||||
virtual void setState(VideoState state) = 0;
|
||||
virtual void setPreferredAspectRatio(float aspectRatio) = 0;
|
||||
|
|
|
@ -162,12 +162,11 @@ void VideoCaptureInterfaceObject::setRotationUpdated(std::function<void(int)> ro
|
|||
_rotationUpdated = rotationUpdated;
|
||||
}
|
||||
|
||||
VideoCaptureInterfaceImpl::VideoCaptureInterfaceImpl(std::string deviceId,
|
||||
std::shared_ptr<PlatformContext> platformContext, std::shared_ptr<Threads> threads) :
|
||||
VideoCaptureInterfaceImpl::VideoCaptureInterfaceImpl(std::string deviceId, bool isScreenCapture, std::shared_ptr<PlatformContext> platformContext, std::shared_ptr<Threads> threads) :
|
||||
_platformContext(platformContext),
|
||||
_impl(threads->getMediaThread(), [deviceId, platformContext, threads]() {
|
||||
return new VideoCaptureInterfaceObject(deviceId, platformContext, *threads);
|
||||
}) {
|
||||
}), _isScreenCapture(isScreenCapture) {
|
||||
}
|
||||
|
||||
VideoCaptureInterfaceImpl::~VideoCaptureInterfaceImpl() = default;
|
||||
|
@ -178,6 +177,10 @@ void VideoCaptureInterfaceImpl::switchToDevice(std::string deviceId) {
|
|||
});
|
||||
}
|
||||
|
||||
bool VideoCaptureInterfaceImpl::isScreenCapture() {
|
||||
return _isScreenCapture;
|
||||
}
|
||||
|
||||
void VideoCaptureInterfaceImpl::withNativeImplementation(std::function<void(void *)> completion) {
|
||||
_impl.perform(RTC_FROM_HERE, [completion](VideoCaptureInterfaceObject *impl) {
|
||||
impl->withNativeImplementation(completion);
|
||||
|
|
|
@ -50,9 +50,10 @@ private:
|
|||
|
||||
class VideoCaptureInterfaceImpl : public VideoCaptureInterface {
|
||||
public:
|
||||
VideoCaptureInterfaceImpl(std::string deviceId, std::shared_ptr<PlatformContext> platformContext, std::shared_ptr<Threads> threads);
|
||||
VideoCaptureInterfaceImpl(std::string deviceId, bool isScreenCapture, std::shared_ptr<PlatformContext> platformContext, std::shared_ptr<Threads> threads);
|
||||
virtual ~VideoCaptureInterfaceImpl();
|
||||
|
||||
bool isScreenCapture() override;
|
||||
void switchToDevice(std::string deviceId) override;
|
||||
void withNativeImplementation(std::function<void(void *)> completion) override;
|
||||
void setState(VideoState state) override;
|
||||
|
@ -67,7 +68,10 @@ public:
|
|||
|
||||
private:
|
||||
ThreadLocalObject<VideoCaptureInterfaceObject> _impl;
|
||||
std::shared_ptr<PlatformContext> _platformContext;
|
||||
|
||||
bool _isScreenCapture = false;
|
||||
|
||||
std::shared_ptr<PlatformContext> _platformContext;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -651,6 +651,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::weak_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>>> getSinks() {
|
||||
return _sinks;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::weak_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>>> _sinks;
|
||||
absl::optional<webrtc::VideoFrame> _lastFrame;
|
||||
|
@ -784,23 +788,25 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
_externalAudioSamplesMutex->Lock();
|
||||
if (!_externalAudioSamples->empty()) {
|
||||
float *bufferData = buffer->channels()[0];
|
||||
int takenSamples = 0;
|
||||
for (int i = 0; i < _externalAudioSamples->size() && i < _frameSamples.size(); i++) {
|
||||
float sample = (*_externalAudioSamples)[i];
|
||||
sample += bufferData[i];
|
||||
sample = std::min(sample, 32768.f);
|
||||
sample = std::max(sample, -32768.f);
|
||||
bufferData[i] = sample;
|
||||
takenSamples++;
|
||||
}
|
||||
if (takenSamples != 0) {
|
||||
_externalAudioSamples->erase(_externalAudioSamples->begin(), _externalAudioSamples->begin() + takenSamples);
|
||||
if (_externalAudioSamplesMutex && _externalAudioSamples) {
|
||||
_externalAudioSamplesMutex->Lock();
|
||||
if (!_externalAudioSamples->empty()) {
|
||||
float *bufferData = buffer->channels()[0];
|
||||
int takenSamples = 0;
|
||||
for (int i = 0; i < _externalAudioSamples->size() && i < _frameSamples.size(); i++) {
|
||||
float sample = (*_externalAudioSamples)[i];
|
||||
sample += bufferData[i];
|
||||
sample = std::min(sample, 32768.f);
|
||||
sample = std::max(sample, -32768.f);
|
||||
bufferData[i] = sample;
|
||||
takenSamples++;
|
||||
}
|
||||
if (takenSamples != 0) {
|
||||
_externalAudioSamples->erase(_externalAudioSamples->begin(), _externalAudioSamples->begin() + takenSamples);
|
||||
}
|
||||
}
|
||||
_externalAudioSamplesMutex->Unlock();
|
||||
}
|
||||
_externalAudioSamplesMutex->Unlock();
|
||||
}
|
||||
|
||||
virtual std::string ToString() const override {
|
||||
|
@ -1100,6 +1106,10 @@ public:
|
|||
_videoSink->addSink(impl);
|
||||
}
|
||||
|
||||
std::vector<std::weak_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>>> getSinks() {
|
||||
return _videoSink->getSinks();
|
||||
}
|
||||
|
||||
std::string const &endpointId() {
|
||||
return _endpointId;
|
||||
}
|
||||
|
@ -1331,7 +1341,9 @@ public:
|
|||
}, threads);
|
||||
}));
|
||||
|
||||
#if USE_RNNOISE
|
||||
std::unique_ptr<AudioCapturePostProcessor> audioProcessor = nullptr;
|
||||
#endif
|
||||
if (_videoContentType != VideoContentType::Screencast) {
|
||||
PlatformInterface::SharedInstance()->configurePlatformAudio();
|
||||
|
||||
|
@ -1344,11 +1356,14 @@ public:
|
|||
}
|
||||
strong->_myAudioLevel = level;
|
||||
});
|
||||
}, _noiseSuppressionConfiguration, &_externalAudioSamples, &_externalAudioSamplesMutex);
|
||||
}, _noiseSuppressionConfiguration, nullptr, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
_threads->getWorkerThread()->Invoke<void>(RTC_FROM_HERE, [this, audioProcessor = std::move(audioProcessor)
|
||||
_threads->getWorkerThread()->Invoke<void>(RTC_FROM_HERE, [this
|
||||
#if USE_RNNOISE
|
||||
, audioProcessor = std::move(audioProcessor)
|
||||
#endif
|
||||
]() mutable {
|
||||
cricket::MediaEngineDependencies mediaDeps;
|
||||
mediaDeps.task_queue_factory = _taskQueueFactory.get();
|
||||
|
@ -1358,12 +1373,14 @@ public:
|
|||
mediaDeps.video_encoder_factory = PlatformInterface::SharedInstance()->makeVideoEncoderFactory(_platformContext);
|
||||
mediaDeps.video_decoder_factory = PlatformInterface::SharedInstance()->makeVideoDecoderFactory(_platformContext);
|
||||
|
||||
#if USE_RNNOISE
|
||||
if (_audioLevelsUpdated && audioProcessor) {
|
||||
webrtc::AudioProcessingBuilder builder;
|
||||
builder.SetCapturePostProcessing(std::move(audioProcessor));
|
||||
|
||||
mediaDeps.audio_processing = builder.Create();
|
||||
}
|
||||
#endif
|
||||
|
||||
_audioDeviceModule = createAudioDeviceModule();
|
||||
if (!_audioDeviceModule) {
|
||||
|
@ -1546,7 +1563,7 @@ public:
|
|||
rtpParameters.encodings[i].scale_resolution_down_by = 4.0;
|
||||
rtpParameters.encodings[i].active = _outgoingVideoConstraint >= 180;
|
||||
} else if (i == 1) {
|
||||
rtpParameters.encodings[i].max_bitrate_bps = 150000;
|
||||
rtpParameters.encodings[i].min_bitrate_bps = 150000;
|
||||
rtpParameters.encodings[i].max_bitrate_bps = 200000;
|
||||
rtpParameters.encodings[i].scale_resolution_down_by = 2.0;
|
||||
rtpParameters.encodings[i].active = _outgoingVideoConstraint >= 360;
|
||||
|
@ -1584,7 +1601,7 @@ public:
|
|||
rtpParameters.encodings[i].scale_resolution_down_by = 4.0;
|
||||
rtpParameters.encodings[i].active = _outgoingVideoConstraint >= 180;
|
||||
} else if (i == 1) {
|
||||
rtpParameters.encodings[i].max_bitrate_bps = 100000;
|
||||
rtpParameters.encodings[i].min_bitrate_bps = 100000;
|
||||
rtpParameters.encodings[i].max_bitrate_bps = 110000;
|
||||
rtpParameters.encodings[i].scale_resolution_down_by = 2.0;
|
||||
rtpParameters.encodings[i].active = _outgoingVideoConstraint >= 360;
|
||||
|
@ -2890,35 +2907,9 @@ public:
|
|||
}
|
||||
|
||||
void removeSsrcs(std::vector<uint32_t> ssrcs) {
|
||||
/*bool updatedIncomingVideoChannels = false;
|
||||
|
||||
for (auto ssrc : ssrcs) {
|
||||
auto it = _ssrcMapping.find(ssrc);
|
||||
if (it != _ssrcMapping.end()) {
|
||||
auto mainSsrc = it->second.ssrc;
|
||||
auto audioChannel = _incomingAudioChannels.find(ChannelId(mainSsrc));
|
||||
if (audioChannel != _incomingAudioChannels.end()) {
|
||||
_incomingAudioChannels.erase(audioChannel);
|
||||
}
|
||||
auto videoChannel = _incomingVideoChannels.find(mainSsrc);
|
||||
if (videoChannel != _incomingVideoChannels.end()) {
|
||||
_incomingVideoChannels.erase(videoChannel);
|
||||
updatedIncomingVideoChannels = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedIncomingVideoChannels) {
|
||||
updateIncomingVideoSources();
|
||||
}*/
|
||||
}
|
||||
|
||||
void removeIncomingVideoSource(uint32_t ssrc) {
|
||||
/*auto videoChannel = _incomingVideoChannels.find(ssrc);
|
||||
if (videoChannel != _incomingVideoChannels.end()) {
|
||||
_incomingVideoChannels.erase(videoChannel);
|
||||
updateIncomingVideoSources();
|
||||
}*/
|
||||
}
|
||||
|
||||
void setIsMuted(bool isMuted) {
|
||||
|
@ -3199,7 +3190,14 @@ public:
|
|||
}
|
||||
|
||||
for (const auto &endpointId : removeEndpointIds) {
|
||||
_incomingVideoChannels.erase(VideoChannelId(endpointId));
|
||||
const auto it = _incomingVideoChannels.find(VideoChannelId(endpointId));
|
||||
if (it != _incomingVideoChannels.end()) {
|
||||
auto sinks = it->second->getSinks();
|
||||
for (const auto &sink : sinks) {
|
||||
_pendingVideoSinks[VideoChannelId(endpointId)].push_back(sink);
|
||||
}
|
||||
_incomingVideoChannels.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_device/android/audio_merged_screen_record_jni.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "modules/audio_device/android/audio_common.h"
|
||||
#include "rtc_base/arraysize.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/format_macros.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/platform_thread.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#include "system_wrappers/include/metrics.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
// Scoped class which logs its time of life as a UMA statistic. It generates
|
||||
// a histogram which measures the time it takes for a method/scope to execute.
|
||||
class ScopedHistogramTimer {
|
||||
public:
|
||||
explicit ScopedHistogramTimer(const std::string& name)
|
||||
: histogram_name_(name), start_time_ms_(rtc::TimeMillis()) {}
|
||||
~ScopedHistogramTimer() {
|
||||
const int64_t life_time_ms = rtc::TimeSince(start_time_ms_);
|
||||
RTC_HISTOGRAM_COUNTS_1000(histogram_name_, life_time_ms);
|
||||
RTC_LOG(INFO) << histogram_name_ << ": " << life_time_ms;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string histogram_name_;
|
||||
int64_t start_time_ms_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// AudioRecordJni::JavaAudioRecord implementation.
|
||||
AudioMergedScreenRecordJni::JavaAudioRecord::JavaAudioRecord(
|
||||
NativeRegistration* native_reg,
|
||||
std::unique_ptr<GlobalRef> audio_record)
|
||||
: audio_record_(std::move(audio_record)),
|
||||
init_recording_(native_reg->GetMethodId("initRecording", "(II)I")),
|
||||
start_recording_(native_reg->GetMethodId("startRecording", "()Z")),
|
||||
stop_recording_(native_reg->GetMethodId("stopRecording", "()Z")),
|
||||
enable_built_in_aec_(native_reg->GetMethodId("enableBuiltInAEC", "(Z)Z")),
|
||||
enable_built_in_ns_(native_reg->GetMethodId("enableBuiltInNS", "(Z)Z")),
|
||||
on_destroy_(native_reg->GetMethodId("onDestroy", "()V")) {}
|
||||
|
||||
AudioMergedScreenRecordJni::JavaAudioRecord::~JavaAudioRecord() {
|
||||
audio_record_->CallVoidMethod(on_destroy_);
|
||||
}
|
||||
|
||||
int AudioMergedScreenRecordJni::JavaAudioRecord::InitRecording(int sample_rate,
|
||||
size_t channels) {
|
||||
return audio_record_->CallIntMethod(init_recording_,
|
||||
static_cast<jint>(sample_rate),
|
||||
static_cast<jint>(channels));
|
||||
}
|
||||
|
||||
bool AudioMergedScreenRecordJni::JavaAudioRecord::StartRecording() {
|
||||
return audio_record_->CallBooleanMethod(start_recording_);
|
||||
}
|
||||
|
||||
bool AudioMergedScreenRecordJni::JavaAudioRecord::StopRecording() {
|
||||
return audio_record_->CallBooleanMethod(stop_recording_);
|
||||
}
|
||||
|
||||
bool AudioMergedScreenRecordJni::JavaAudioRecord::EnableBuiltInAEC(bool enable) {
|
||||
return audio_record_->CallBooleanMethod(enable_built_in_aec_,
|
||||
static_cast<jboolean>(enable));
|
||||
}
|
||||
|
||||
bool AudioMergedScreenRecordJni::JavaAudioRecord::EnableBuiltInNS(bool enable) {
|
||||
return audio_record_->CallBooleanMethod(enable_built_in_ns_,
|
||||
static_cast<jboolean>(enable));
|
||||
}
|
||||
|
||||
// AudioRecordJni implementation.
|
||||
AudioMergedScreenRecordJni::AudioMergedScreenRecordJni(AudioManager* audio_manager)
|
||||
: j_environment_(JVM::GetInstance()->environment()),
|
||||
audio_manager_(audio_manager),
|
||||
audio_parameters_(audio_manager->GetRecordAudioParameters()),
|
||||
total_delay_in_milliseconds_(0),
|
||||
direct_buffer_address_(nullptr),
|
||||
direct_buffer_capacity_in_bytes_(0),
|
||||
frames_per_buffer_(0),
|
||||
initialized_(false),
|
||||
recording_(false),
|
||||
audio_device_buffer_(nullptr) {
|
||||
RTC_LOG(INFO) << "ctor";
|
||||
RTC_DCHECK(audio_parameters_.is_valid());
|
||||
RTC_CHECK(j_environment_);
|
||||
JNINativeMethod native_methods[] = {
|
||||
{"nativeCacheDirectBufferAddress", "(Ljava/nio/ByteBuffer;J)V",
|
||||
reinterpret_cast<void*>(
|
||||
&webrtc::AudioMergedScreenRecordJni::CacheDirectBufferAddress)},
|
||||
{"nativeDataIsRecorded", "(IJ)V",
|
||||
reinterpret_cast<void*>(&webrtc::AudioMergedScreenRecordJni::DataIsRecorded)}};
|
||||
j_native_registration_ = j_environment_->RegisterNatives(
|
||||
"org/webrtc/voiceengine/WebRtcAudioRecord", native_methods,
|
||||
arraysize(native_methods));
|
||||
j_audio_record_.reset(
|
||||
new JavaAudioRecord(j_native_registration_.get(),
|
||||
j_native_registration_->NewObject(
|
||||
"<init>", "(JI)V", PointerTojlong(this), 2)));
|
||||
// Detach from this thread since we want to use the checker to verify calls
|
||||
// from the Java based audio thread.
|
||||
thread_checker_java_.Detach();
|
||||
}
|
||||
|
||||
AudioMergedScreenRecordJni::~AudioMergedScreenRecordJni() {
|
||||
RTC_LOG(INFO) << "dtor";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
Terminate();
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::Init() {
|
||||
RTC_LOG(INFO) << "Init";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::Terminate() {
|
||||
RTC_LOG(INFO) << "Terminate";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
StopRecording();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::InitRecording() {
|
||||
RTC_LOG(INFO) << "InitRecording";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
RTC_DCHECK(!initialized_);
|
||||
RTC_DCHECK(!recording_);
|
||||
ScopedHistogramTimer timer("WebRTC.Audio.InitRecordingDurationMs");
|
||||
int frames_per_buffer = j_audio_record_->InitRecording(
|
||||
audio_parameters_.sample_rate(), audio_parameters_.channels());
|
||||
if (frames_per_buffer < 0) {
|
||||
direct_buffer_address_ = nullptr;
|
||||
RTC_LOG(LS_ERROR) << "InitRecording failed";
|
||||
return -1;
|
||||
}
|
||||
frames_per_buffer_ = static_cast<size_t>(frames_per_buffer);
|
||||
RTC_LOG(INFO) << "frames_per_buffer: " << frames_per_buffer_;
|
||||
const size_t bytes_per_frame = audio_parameters_.channels() * sizeof(int16_t);
|
||||
RTC_CHECK_EQ(direct_buffer_capacity_in_bytes_,
|
||||
frames_per_buffer_ * bytes_per_frame);
|
||||
RTC_CHECK_EQ(frames_per_buffer_, audio_parameters_.frames_per_10ms_buffer());
|
||||
initialized_ = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::StartRecording() {
|
||||
RTC_LOG(INFO) << "StartRecording";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
RTC_DCHECK(!recording_);
|
||||
if (!initialized_) {
|
||||
RTC_DLOG(LS_WARNING)
|
||||
<< "Recording can not start since InitRecording must succeed first";
|
||||
return 0;
|
||||
}
|
||||
ScopedHistogramTimer timer("WebRTC.Audio.StartRecordingDurationMs");
|
||||
if (!j_audio_record_->StartRecording()) {
|
||||
RTC_LOG(LS_ERROR) << "StartRecording failed";
|
||||
return -1;
|
||||
}
|
||||
recording_ = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::StopRecording() {
|
||||
RTC_LOG(INFO) << "StopRecording";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
if (!initialized_ || !recording_) {
|
||||
return 0;
|
||||
}
|
||||
if (!j_audio_record_->StopRecording()) {
|
||||
RTC_LOG(LS_ERROR) << "StopRecording failed";
|
||||
return -1;
|
||||
}
|
||||
// If we don't detach here, we will hit a RTC_DCHECK in OnDataIsRecorded()
|
||||
// next time StartRecording() is called since it will create a new Java
|
||||
// thread.
|
||||
thread_checker_java_.Detach();
|
||||
initialized_ = false;
|
||||
recording_ = false;
|
||||
direct_buffer_address_ = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AudioMergedScreenRecordJni::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
|
||||
RTC_LOG(INFO) << "AttachAudioBuffer";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
audio_device_buffer_ = audioBuffer;
|
||||
const int sample_rate_hz = audio_parameters_.sample_rate();
|
||||
RTC_LOG(INFO) << "SetRecordingSampleRate(" << sample_rate_hz << ")";
|
||||
audio_device_buffer_->SetRecordingSampleRate(sample_rate_hz);
|
||||
const size_t channels = audio_parameters_.channels();
|
||||
RTC_LOG(INFO) << "SetRecordingChannels(" << channels << ")";
|
||||
audio_device_buffer_->SetRecordingChannels(channels);
|
||||
total_delay_in_milliseconds_ =
|
||||
audio_manager_->GetDelayEstimateInMilliseconds();
|
||||
RTC_DCHECK_GT(total_delay_in_milliseconds_, 0);
|
||||
RTC_LOG(INFO) << "total_delay_in_milliseconds: "
|
||||
<< total_delay_in_milliseconds_;
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::EnableBuiltInAEC(bool enable) {
|
||||
RTC_LOG(INFO) << "EnableBuiltInAEC(" << enable << ")";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
return j_audio_record_->EnableBuiltInAEC(enable) ? 0 : -1;
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::EnableBuiltInAGC(bool enable) {
|
||||
// TODO(henrika): possibly remove when no longer used by any client.
|
||||
RTC_CHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
int32_t AudioMergedScreenRecordJni::EnableBuiltInNS(bool enable) {
|
||||
RTC_LOG(INFO) << "EnableBuiltInNS(" << enable << ")";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
return j_audio_record_->EnableBuiltInNS(enable) ? 0 : -1;
|
||||
}
|
||||
|
||||
JNI_FUNCTION_ALIGN
|
||||
void JNICALL AudioMergedScreenRecordJni::CacheDirectBufferAddress(JNIEnv* env,
|
||||
jobject obj,
|
||||
jobject byte_buffer,
|
||||
jlong nativeAudioRecord) {
|
||||
webrtc::AudioMergedScreenRecordJni* this_object =
|
||||
reinterpret_cast<webrtc::AudioMergedScreenRecordJni*>(nativeAudioRecord);
|
||||
this_object->OnCacheDirectBufferAddress(env, byte_buffer);
|
||||
}
|
||||
|
||||
void AudioMergedScreenRecordJni::OnCacheDirectBufferAddress(JNIEnv* env,
|
||||
jobject byte_buffer) {
|
||||
RTC_LOG(INFO) << "OnCacheDirectBufferAddress";
|
||||
RTC_DCHECK(thread_checker_.IsCurrent());
|
||||
RTC_DCHECK(!direct_buffer_address_);
|
||||
direct_buffer_address_ = env->GetDirectBufferAddress(byte_buffer);
|
||||
jlong capacity = env->GetDirectBufferCapacity(byte_buffer);
|
||||
RTC_LOG(INFO) << "direct buffer capacity: " << capacity;
|
||||
direct_buffer_capacity_in_bytes_ = static_cast<size_t>(capacity);
|
||||
}
|
||||
|
||||
JNI_FUNCTION_ALIGN
|
||||
void JNICALL AudioMergedScreenRecordJni::DataIsRecorded(JNIEnv* env,
|
||||
jobject obj,
|
||||
jint length,
|
||||
jlong nativeAudioRecord) {
|
||||
webrtc::AudioMergedScreenRecordJni* this_object =
|
||||
reinterpret_cast<webrtc::AudioMergedScreenRecordJni*>(nativeAudioRecord);
|
||||
this_object->OnDataIsRecorded(length);
|
||||
}
|
||||
|
||||
// This method is called on a high-priority thread from Java. The name of
|
||||
// the thread is 'AudioRecordThread'.
|
||||
void AudioMergedScreenRecordJni::OnDataIsRecorded(int length) {
|
||||
RTC_DCHECK(thread_checker_java_.IsCurrent());
|
||||
if (!audio_device_buffer_) {
|
||||
RTC_LOG(LS_ERROR) << "AttachAudioBuffer has not been called";
|
||||
return;
|
||||
}
|
||||
audio_device_buffer_->SetRecordedBuffer(direct_buffer_address_,
|
||||
frames_per_buffer_);
|
||||
// We provide one (combined) fixed delay estimate for the APM and use the
|
||||
// |playDelayMs| parameter only. Components like the AEC only sees the sum
|
||||
// of |playDelayMs| and |recDelayMs|, hence the distributions does not matter.
|
||||
audio_device_buffer_->SetVQEData(total_delay_in_milliseconds_, 0);
|
||||
if (audio_device_buffer_->DeliverRecordedData() == -1) {
|
||||
RTC_LOG(INFO) << "AudioDeviceBuffer::DeliverRecordedData failed";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_DEVICE_ANDROID_AUDIO_MERGED_SCREEN_RECORD_JNI_H_
|
||||
#define MODULES_AUDIO_DEVICE_ANDROID_AUDIO_MERGED_SCREEN_RECORD_JNI_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/sequence_checker.h"
|
||||
#include "modules/audio_device/android/audio_manager.h"
|
||||
#include "modules/audio_device/audio_device_generic.h"
|
||||
#include "modules/audio_device/include/audio_device_defines.h"
|
||||
#include "modules/utility/include/helpers_android.h"
|
||||
#include "modules/utility/include/jvm_android.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Implements 16-bit mono PCM audio input support for Android using the Java
|
||||
// AudioRecord interface. Most of the work is done by its Java counterpart in
|
||||
// WebRtcAudioRecord.java. This class is created and lives on a thread in
|
||||
// C++-land, but recorded audio buffers are delivered on a high-priority
|
||||
// thread managed by the Java class.
|
||||
//
|
||||
// The Java class makes use of AudioEffect features (mainly AEC) which are
|
||||
// first available in Jelly Bean. If it is instantiated running against earlier
|
||||
// SDKs, the AEC provided by the APM in WebRTC must be used and enabled
|
||||
// separately instead.
|
||||
//
|
||||
// An instance must be created and destroyed on one and the same thread.
|
||||
// All public methods must also be called on the same thread. A thread checker
|
||||
// will RTC_DCHECK if any method is called on an invalid thread.
|
||||
//
|
||||
// This class uses JvmThreadConnector to attach to a Java VM if needed
|
||||
// and detach when the object goes out of scope. Additional thread checking
|
||||
// guarantees that no other (possibly non attached) thread is used.
|
||||
class AudioMergedScreenRecordJni {
|
||||
public:
|
||||
// Wraps the Java specific parts of the AudioRecordJni into one helper class.
|
||||
class JavaAudioRecord {
|
||||
public:
|
||||
JavaAudioRecord(NativeRegistration* native_registration,
|
||||
std::unique_ptr<GlobalRef> audio_track);
|
||||
~JavaAudioRecord();
|
||||
|
||||
int InitRecording(int sample_rate, size_t channels);
|
||||
bool StartRecording();
|
||||
bool StopRecording();
|
||||
bool EnableBuiltInAEC(bool enable);
|
||||
bool EnableBuiltInNS(bool enable);
|
||||
|
||||
private:
|
||||
std::unique_ptr<GlobalRef> audio_record_;
|
||||
jmethodID init_recording_;
|
||||
jmethodID start_recording_;
|
||||
jmethodID stop_recording_;
|
||||
jmethodID enable_built_in_aec_;
|
||||
jmethodID enable_built_in_ns_;
|
||||
jmethodID on_destroy_;
|
||||
};
|
||||
|
||||
explicit AudioMergedScreenRecordJni(AudioManager* audio_manager);
|
||||
~AudioMergedScreenRecordJni();
|
||||
|
||||
int32_t Init();
|
||||
int32_t Terminate();
|
||||
|
||||
int32_t InitRecording();
|
||||
bool RecordingIsInitialized() const { return initialized_; }
|
||||
|
||||
int32_t StartRecording();
|
||||
int32_t StopRecording();
|
||||
bool Recording() const { return recording_; }
|
||||
|
||||
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer);
|
||||
|
||||
int32_t EnableBuiltInAEC(bool enable);
|
||||
int32_t EnableBuiltInAGC(bool enable);
|
||||
int32_t EnableBuiltInNS(bool enable);
|
||||
|
||||
private:
|
||||
// Called from Java side so we can cache the address of the Java-manged
|
||||
// |byte_buffer| in |direct_buffer_address_|. The size of the buffer
|
||||
// is also stored in |direct_buffer_capacity_in_bytes_|.
|
||||
// This method will be called by the WebRtcAudioRecord constructor, i.e.,
|
||||
// on the same thread that this object is created on.
|
||||
static void JNICALL CacheDirectBufferAddress(JNIEnv* env,
|
||||
jobject obj,
|
||||
jobject byte_buffer,
|
||||
jlong nativeAudioRecord);
|
||||
void OnCacheDirectBufferAddress(JNIEnv* env, jobject byte_buffer);
|
||||
|
||||
// Called periodically by the Java based WebRtcAudioRecord object when
|
||||
// recording has started. Each call indicates that there are |length| new
|
||||
// bytes recorded in the memory area |direct_buffer_address_| and it is
|
||||
// now time to send these to the consumer.
|
||||
// This method is called on a high-priority thread from Java. The name of
|
||||
// the thread is 'AudioRecordThread'.
|
||||
static void JNICALL DataIsRecorded(JNIEnv* env,
|
||||
jobject obj,
|
||||
jint length,
|
||||
jlong nativeAudioRecord);
|
||||
void OnDataIsRecorded(int length);
|
||||
|
||||
// Stores thread ID in constructor.
|
||||
SequenceChecker thread_checker_;
|
||||
|
||||
// Stores thread ID in first call to OnDataIsRecorded() from high-priority
|
||||
// thread in Java. Detached during construction of this object.
|
||||
SequenceChecker thread_checker_java_;
|
||||
|
||||
// Calls JavaVM::AttachCurrentThread() if this thread is not attached at
|
||||
// construction.
|
||||
// Also ensures that DetachCurrentThread() is called at destruction.
|
||||
JvmThreadConnector attach_thread_if_needed_;
|
||||
|
||||
// Wraps the JNI interface pointer and methods associated with it.
|
||||
std::unique_ptr<JNIEnvironment> j_environment_;
|
||||
|
||||
// Contains factory method for creating the Java object.
|
||||
std::unique_ptr<NativeRegistration> j_native_registration_;
|
||||
|
||||
// Wraps the Java specific parts of the AudioRecordJni class.
|
||||
std::unique_ptr<AudioMergedScreenRecordJni::JavaAudioRecord> j_audio_record_;
|
||||
|
||||
// Raw pointer to the audio manger.
|
||||
const AudioManager* audio_manager_;
|
||||
|
||||
// Contains audio parameters provided to this class at construction by the
|
||||
// AudioManager.
|
||||
const AudioParameters audio_parameters_;
|
||||
|
||||
// Delay estimate of the total round-trip delay (input + output).
|
||||
// Fixed value set once in AttachAudioBuffer() and it can take one out of two
|
||||
// possible values. See audio_common.h for details.
|
||||
int total_delay_in_milliseconds_;
|
||||
|
||||
// Cached copy of address to direct audio buffer owned by |j_audio_record_|.
|
||||
void* direct_buffer_address_;
|
||||
|
||||
// Number of bytes in the direct audio buffer owned by |j_audio_record_|.
|
||||
size_t direct_buffer_capacity_in_bytes_;
|
||||
|
||||
// Number audio frames per audio buffer. Each audio frame corresponds to
|
||||
// one sample of PCM mono data at 16 bits per sample. Hence, each audio
|
||||
// frame contains 2 bytes (given that the Java layer only supports mono).
|
||||
// Example: 480 for 48000 Hz or 441 for 44100 Hz.
|
||||
size_t frames_per_buffer_;
|
||||
|
||||
bool initialized_;
|
||||
|
||||
bool recording_;
|
||||
|
||||
// Raw pointer handle provided to us in AttachAudioBuffer(). Owned by the
|
||||
// AudioDeviceModuleImpl class and called by AudioDeviceModule::Create().
|
||||
AudioDeviceBuffer* audio_device_buffer_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_DEVICE_ANDROID_AUDIO_RECORD_JNI_H_
|
|
@ -106,7 +106,7 @@ AudioRecordJni::AudioRecordJni(AudioManager* audio_manager)
|
|||
j_audio_record_.reset(
|
||||
new JavaAudioRecord(j_native_registration_.get(),
|
||||
j_native_registration_->NewObject(
|
||||
"<init>", "(JZ)V", PointerTojlong(this), false)));
|
||||
"<init>", "(JI)V", PointerTojlong(this), 0)));
|
||||
// Detach from this thread since we want to use the checker to verify calls
|
||||
// from the Java based audio thread.
|
||||
thread_checker_java_.Detach();
|
||||
|
|
|
@ -106,7 +106,7 @@ AudioScreenRecordJni::AudioScreenRecordJni(AudioManager* audio_manager)
|
|||
j_audio_record_.reset(
|
||||
new JavaAudioRecord(j_native_registration_.get(),
|
||||
j_native_registration_->NewObject(
|
||||
"<init>", "(JZ)V", PointerTojlong(this), true)));
|
||||
"<init>", "(JI)V", PointerTojlong(this), 1)));
|
||||
// Detach from this thread since we want to use the checker to verify calls
|
||||
// from the Java based audio thread.
|
||||
thread_checker_java_.Detach();
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "modules/audio_device/android/audio_manager.h"
|
||||
#include "modules/audio_device/android/audio_record_jni.h"
|
||||
#include "modules/audio_device/android/audio_screen_record_jni.h"
|
||||
#include "modules/audio_device/android/audio_merged_screen_record_jni.h"
|
||||
#include "modules/audio_device/android/audio_track_jni.h"
|
||||
#include "modules/audio_device/android/opensles_player.h"
|
||||
#include "modules/audio_device/android/opensles_recorder.h"
|
||||
|
@ -215,6 +216,10 @@ int32_t AudioDeviceModuleImpl::CreatePlatformSpecificObjects() {
|
|||
// Java audio for both input and output audio.
|
||||
audio_device_.reset(new AudioDeviceTemplate<AudioScreenRecordJni, AudioTrackJni>(
|
||||
audio_layer, audio_manager));
|
||||
} else if (audio_layer == kAndroidMergedScreenAudio) {
|
||||
// Java audio for both input and output audio.
|
||||
audio_device_.reset(new AudioDeviceTemplate<AudioMergedScreenRecordJni, AudioTrackJni>(
|
||||
audio_layer, audio_manager));
|
||||
} else if (audio_layer == kAndroidOpenSLESAudio) {
|
||||
// OpenSL ES based audio for both input and output audio.
|
||||
audio_device_.reset(
|
||||
|
|
|
@ -34,7 +34,8 @@ class AudioDeviceModule : public rtc::RefCountInterface {
|
|||
kAndroidAAudioAudio,
|
||||
kAndroidJavaInputAndAAudioOutputAudio,
|
||||
kDummyAudio,
|
||||
kAndroidScreenAudio
|
||||
kAndroidScreenAudio,
|
||||
kAndroidMergedScreenAudio
|
||||
};
|
||||
|
||||
enum WindowsDeviceType {
|
||||
|
|
|
@ -15,6 +15,8 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.ImageReceiver;
|
||||
|
@ -392,6 +394,20 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
|
|||
fromX += (int) holder.itemView.getTranslationX();
|
||||
}
|
||||
fromY += (int) holder.itemView.getTranslationY();
|
||||
float imageX = 0;
|
||||
float imageY = 0;
|
||||
float imageW = 0;
|
||||
float imageH = 0;
|
||||
int[] roundRadius = new int[4];
|
||||
if (chatMessageCell != null) {
|
||||
imageX = chatMessageCell.getPhotoImage().getImageX();
|
||||
imageY = chatMessageCell.getPhotoImage().getImageY();
|
||||
imageW = chatMessageCell.getPhotoImage().getImageWidth();
|
||||
imageH = chatMessageCell.getPhotoImage().getImageHeight();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
roundRadius[i] = chatMessageCell.getPhotoImage().getRoundRadius()[i];
|
||||
}
|
||||
}
|
||||
resetAnimation(holder);
|
||||
int deltaX = toX - fromX;
|
||||
int deltaY = toY - fromY;
|
||||
|
@ -431,12 +447,20 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
|
|||
recyclerListView.invalidate();
|
||||
|
||||
params.imageChangeBoundsTransition = true;
|
||||
params.animateToImageX = newImage.getImageX();
|
||||
params.animateToImageY = newImage.getImageY();
|
||||
params.animateToImageW = newImage.getImageWidth();
|
||||
params.animateToImageH = newImage.getImageHeight();
|
||||
if (chatMessageCell.getMessageObject().isRoundVideo()) {
|
||||
params.animateToImageX = imageX;
|
||||
params.animateToImageY = imageY;
|
||||
params.animateToImageW = imageW;
|
||||
params.animateToImageH = imageH;
|
||||
params.animateToRadius = roundRadius;
|
||||
} else {
|
||||
params.animateToImageX = newImage.getImageX();
|
||||
params.animateToImageY = newImage.getImageY();
|
||||
params.animateToImageW = newImage.getImageWidth();
|
||||
params.animateToImageH = newImage.getImageHeight();
|
||||
params.animateToRadius = newImage.getRoundRadius();
|
||||
}
|
||||
|
||||
params.animateToRadius = newImage.getRoundRadius();
|
||||
params.animateRadius = false;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (params.imageRoundRadius[i] != params.animateToRadius[i]) {
|
||||
|
@ -458,9 +482,11 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
|
|||
group.transitionParams.captionEnterProgress = group.transitionParams.drawCaptionLayout ? 1f : 0;
|
||||
}
|
||||
if (params.animateRadius) {
|
||||
params.animateToRadius = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
params.animateToRadius[i] = newImage.getRoundRadius()[i];
|
||||
if (params.animateToRadius == newImage.getRoundRadius()) {
|
||||
params.animateToRadius = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
params.animateToRadius[i] = newImage.getRoundRadius()[i];
|
||||
}
|
||||
}
|
||||
newImage.setRoundRadius(params.imageRoundRadius);
|
||||
}
|
||||
|
@ -695,6 +721,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
|
|||
}
|
||||
|
||||
int[] finalFromRoundRadius = fromRoundRadius;
|
||||
|
||||
valueAnimator.addUpdateListener(animation -> {
|
||||
float v = (float) animation.getAnimatedValue();
|
||||
float x = moveInfoExtended.imageX * (1f - v) + params.animateToImageX * v;
|
||||
|
@ -723,12 +750,6 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
|
|||
chatMessageCell.setImageCoords(x, y, width, height);
|
||||
holder.itemView.invalidate();
|
||||
});
|
||||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
params.imageChangeBoundsTransition = false;
|
||||
}
|
||||
});
|
||||
animatorSet.playTogether(valueAnimator);
|
||||
}
|
||||
if (moveInfoExtended.deltaBottom != 0 || moveInfoExtended.deltaRight != 0 || moveInfoExtended.deltaTop != 0 || moveInfoExtended.deltaLeft != 0) {
|
||||
|
@ -740,15 +761,15 @@ public class ChatListItemAnimator extends DefaultItemAnimator {
|
|||
valueAnimator.addUpdateListener(animation -> {
|
||||
float v = (float) animation.getAnimatedValue();
|
||||
if (moveInfoExtended.animateBackgroundOnly) {
|
||||
params.deltaLeft = (int) (-moveInfoExtended.deltaLeft * v);
|
||||
params.deltaRight = (int) (-moveInfoExtended.deltaRight * v);
|
||||
params.deltaTop = (int) (-moveInfoExtended.deltaTop * v);
|
||||
params.deltaBottom = (int) (-moveInfoExtended.deltaBottom * v);
|
||||
params.deltaLeft = -moveInfoExtended.deltaLeft * v;
|
||||
params.deltaRight = -moveInfoExtended.deltaRight * v;
|
||||
params.deltaTop = -moveInfoExtended.deltaTop * v;
|
||||
params.deltaBottom = -moveInfoExtended.deltaBottom * v;
|
||||
} else {
|
||||
params.deltaLeft = (int) (-moveInfoExtended.deltaLeft * v - chatMessageCell.getAnimationOffsetX());
|
||||
params.deltaRight = (int) (-moveInfoExtended.deltaRight * v - chatMessageCell.getAnimationOffsetX());
|
||||
params.deltaTop = (int) (-moveInfoExtended.deltaTop * v - chatMessageCell.getTranslationY());
|
||||
params.deltaBottom = (int) (-moveInfoExtended.deltaBottom * v - chatMessageCell.getTranslationY());
|
||||
params.deltaLeft = -moveInfoExtended.deltaLeft * v - chatMessageCell.getAnimationOffsetX();
|
||||
params.deltaRight = -moveInfoExtended.deltaRight * v - chatMessageCell.getAnimationOffsetX();
|
||||
params.deltaTop = -moveInfoExtended.deltaTop * v - chatMessageCell.getTranslationY();
|
||||
params.deltaBottom = -moveInfoExtended.deltaBottom * v - chatMessageCell.getTranslationY();
|
||||
}
|
||||
chatMessageCell.invalidate();
|
||||
});
|
||||
|
|
|
@ -59,7 +59,6 @@ import android.widget.LinearLayout;
|
|||
import android.widget.OverScroller;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.BuildConfig;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.FileLog;
|
||||
|
||||
|
@ -2779,7 +2778,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView,
|
|||
* same View may still get the focus as a result of that search.
|
||||
*/
|
||||
private boolean isPreferredNextFocus(View focused, View next, int direction) {
|
||||
if (next == null || next == this) {
|
||||
if (next == null || next == this || next == focused) {
|
||||
return false;
|
||||
}
|
||||
// panic, result view is not a child anymore, maybe workaround b/37864393
|
||||
|
@ -2829,9 +2828,9 @@ public class RecyclerView extends ViewGroup implements ScrollingView,
|
|||
case View.FOCUS_DOWN:
|
||||
return downness > 0;
|
||||
case View.FOCUS_FORWARD:
|
||||
return downness > 0 || (downness == 0 && rightness * rtl >= 0);
|
||||
return downness > 0 || (downness == 0 && rightness * rtl > 0);
|
||||
case View.FOCUS_BACKWARD:
|
||||
return downness < 0 || (downness == 0 && rightness * rtl <= 0);
|
||||
return downness < 0 || (downness == 0 && rightness * rtl < 0);
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid direction: " + direction + exceptionLabel());
|
||||
}
|
||||
|
@ -5110,7 +5109,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView,
|
|||
// but some general-purpose code may choose to respond to changes this way.
|
||||
final int scrollX = getScrollX();
|
||||
final int scrollY = getScrollY();
|
||||
onScrollChanged(scrollX, scrollY, scrollX, scrollY);
|
||||
onScrollChanged(scrollX, scrollY, scrollX - hresult, scrollY - vresult);
|
||||
|
||||
// Pass the real deltas to onScrolled, the RecyclerView-specific method.
|
||||
onScrolled(hresult, vresult);
|
||||
|
@ -5330,7 +5329,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView,
|
|||
|
||||
postOnAnimation();
|
||||
if (mGapWorker != null) {
|
||||
mGapWorker.postFromTraversal(RecyclerView.this, unconsumedX, unconsumedY);
|
||||
mGapWorker.postFromTraversal(RecyclerView.this, consumedX, consumedY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ import org.telegram.ui.Cells.TextDetailSettingsCell;
|
|||
import org.telegram.ui.Components.BackgroundGradientDrawable;
|
||||
import org.telegram.ui.Components.ForegroundColorSpanThemable;
|
||||
import org.telegram.ui.Components.ForegroundDetector;
|
||||
import org.telegram.ui.Components.HideViewAfterAnimation;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.MotionBackgroundDrawable;
|
||||
import org.telegram.ui.Components.PickerBottomLayout;
|
||||
|
@ -188,6 +189,7 @@ public class AndroidUtilities {
|
|||
public static Point displaySize = new Point();
|
||||
public static float screenRefreshRate = 60;
|
||||
public static int roundMessageSize;
|
||||
public static int roundPlayingMessageSize;
|
||||
public static int roundMessageInset;
|
||||
public static boolean incorrectDisplaySizeFix;
|
||||
public static Integer photoSize = null;
|
||||
|
@ -211,12 +213,14 @@ public class AndroidUtilities {
|
|||
public static Pattern WEB_URL = null;
|
||||
public static Pattern BAD_CHARS_PATTERN = null;
|
||||
public static Pattern BAD_CHARS_MESSAGE_PATTERN = null;
|
||||
public static Pattern BAD_CHARS_MESSAGE_LONG_PATTERN = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
|
||||
BAD_CHARS_PATTERN = Pattern.compile("[\u2500-\u25ff]");
|
||||
BAD_CHARS_MESSAGE_PATTERN = Pattern.compile("[\u0300-\u036f]+");
|
||||
BAD_CHARS_MESSAGE_LONG_PATTERN = Pattern.compile("[\u0300-\u036f\u2066-\u2067]+");
|
||||
BAD_CHARS_MESSAGE_PATTERN = Pattern.compile("[\u2066-\u2067]+");
|
||||
final Pattern IP_ADDRESS = Pattern.compile(
|
||||
"((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
|
||||
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
|
||||
|
@ -280,6 +284,14 @@ public class AndroidUtilities {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static String getSafeString(String str) {
|
||||
try {
|
||||
return BAD_CHARS_MESSAGE_PATTERN.matcher(str).replaceAll("\u200C");
|
||||
} catch (Throwable e) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
public static CharSequence ellipsizeCenterEnd(CharSequence str, String query, int availableWidth, TextPaint textPaint, int maxSymbols) {
|
||||
try {
|
||||
int lastIndex = str.length();
|
||||
|
@ -1661,8 +1673,10 @@ public class AndroidUtilities {
|
|||
if (roundMessageSize == 0) {
|
||||
if (AndroidUtilities.isTablet()) {
|
||||
roundMessageSize = (int) (AndroidUtilities.getMinTabletSide() * 0.6f);
|
||||
roundPlayingMessageSize = (int) (AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(28));
|
||||
} else {
|
||||
roundMessageSize = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.6f);
|
||||
roundPlayingMessageSize = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(28));
|
||||
}
|
||||
roundMessageInset = dp(2);
|
||||
}
|
||||
|
@ -1774,7 +1788,7 @@ public class AndroidUtilities {
|
|||
public static boolean isTablet() {
|
||||
if (isTablet == null) switch (NekoConfig.tabletMode) {
|
||||
case 0:
|
||||
isTablet = ApplicationLoader.applicationContext.getResources().getBoolean(R.bool.isTablet);
|
||||
isTablet = ApplicationLoader.applicationContext != null && ApplicationLoader.applicationContext.getResources().getBoolean(R.bool.isTablet);
|
||||
break;
|
||||
case 1:
|
||||
isTablet = true;
|
||||
|
@ -4325,12 +4339,7 @@ public class AndroidUtilities {
|
|||
} else if (!show && view.getTag() != null){
|
||||
view.animate().setListener(null).cancel();
|
||||
if (animated) {
|
||||
view.animate().alpha(0).scaleY(scaleFactor).scaleX(scaleFactor).setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}).setDuration(150).start();
|
||||
view.animate().alpha(0).scaleY(scaleFactor).scaleX(scaleFactor).setListener(new HideViewAfterAnimation(view)).setDuration(150).start();
|
||||
} else {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
|
|
|
@ -274,7 +274,7 @@ public class ApplicationLoader extends Application {
|
|||
FileLog.d("screen state = " + isScreenOn);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (int a : SharedConfig.activeAccounts) {
|
||||
|
|
|
@ -308,7 +308,6 @@ public class Emoji {
|
|||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
placeholderPaint.setAlpha(alpha);
|
||||
paint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
|
|
|
@ -2297,4 +2297,14 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startCrossfadeFromStaticThumb(Bitmap thumb) {
|
||||
currentThumbKey = null;
|
||||
currentThumbDrawable = null;
|
||||
thumbShader = null;
|
||||
staticThumbDrawable = new BitmapDrawable(null, thumb);
|
||||
crossfadeWithThumb = true;
|
||||
currentAlpha = 0f;
|
||||
updateDrawableRadius(staticThumbDrawable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1184,6 +1184,8 @@ public class LocaleController {
|
|||
return LocaleController.formatPluralString("Hours", ttl / 60 / 60);
|
||||
} else if (ttl < 60 * 60 * 24 * 7) {
|
||||
return LocaleController.formatPluralString("Days", ttl / 60 / 60 / 24);
|
||||
} else if (ttl >= 60 * 60 * 24 * 30 && ttl <= 60 * 60 * 24 * 31) {
|
||||
return LocaleController.formatPluralString("Months", ttl / 60 / 60 / 24 / 30);
|
||||
} else {
|
||||
int days = ttl / 60 / 60 / 24;
|
||||
if (ttl % 7 == 0) {
|
||||
|
|
|
@ -502,6 +502,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
private long lastSaveTime;
|
||||
private float currentPlaybackSpeed = 1.0f;
|
||||
private float currentMusicPlaybackSpeed = 1.0f;
|
||||
private float fastPlaybackSpeed = 1.0f;
|
||||
private float fastMusicPlaybackSpeed = 1.0f;
|
||||
private float seekToProgressPending;
|
||||
private long lastProgress = 0;
|
||||
private MessageObject playingMessageObject;
|
||||
|
@ -893,6 +895,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
try {
|
||||
currentPlaybackSpeed = MessagesController.getGlobalMainSettings().getFloat("playbackSpeed", 1.0f);
|
||||
currentMusicPlaybackSpeed = MessagesController.getGlobalMainSettings().getFloat("musicPlaybackSpeed", 1.0f);
|
||||
fastPlaybackSpeed = MessagesController.getGlobalMainSettings().getFloat("fastPlaybackSpeed", 1.8f);
|
||||
fastMusicPlaybackSpeed = MessagesController.getGlobalMainSettings().getFloat("fastMusicPlaybackSpeed", 1.8f);
|
||||
sensorManager = (SensorManager) ApplicationLoader.applicationContext.getSystemService(Context.SENSOR_SERVICE);
|
||||
linearSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
|
||||
gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
|
||||
|
@ -1043,6 +1047,10 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
}
|
||||
}
|
||||
|
||||
public VideoPlayer getVideoPlayer() {
|
||||
return videoPlayer;
|
||||
}
|
||||
|
||||
private void startProgressTimer(final MessageObject currentPlayingMessageObject) {
|
||||
synchronized (progressTimerSync) {
|
||||
if (progressTimer != null) {
|
||||
|
@ -2528,15 +2536,23 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
}, 50);
|
||||
}
|
||||
currentMusicPlaybackSpeed = speed;
|
||||
if (Math.abs(speed - 1.0f) > 0.001f) {
|
||||
fastMusicPlaybackSpeed = speed;
|
||||
}
|
||||
} else {
|
||||
currentPlaybackSpeed = speed;
|
||||
if (Math.abs(speed - 1.0f) > 0.001f) {
|
||||
fastPlaybackSpeed = speed;
|
||||
}
|
||||
}
|
||||
if (audioPlayer != null) {
|
||||
audioPlayer.setPlaybackSpeed(speed);
|
||||
} else if (videoPlayer != null) {
|
||||
videoPlayer.setPlaybackSpeed(speed);
|
||||
}
|
||||
MessagesController.getGlobalMainSettings().edit().putFloat(music ? "musicPlaybackSpeed" : "playbackSpeed", speed).commit();
|
||||
MessagesController.getGlobalMainSettings().edit()
|
||||
.putFloat(music ? "musicPlaybackSpeed" : "playbackSpeed", speed)
|
||||
.putFloat(music ? "fastMusicPlaybackSpeed" : "fastPlaybackSpeed", music ? fastMusicPlaybackSpeed : fastPlaybackSpeed).commit();
|
||||
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.messagePlayingSpeedChanged);
|
||||
}
|
||||
|
||||
|
@ -2544,6 +2560,10 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
return music ? currentMusicPlaybackSpeed : currentPlaybackSpeed;
|
||||
}
|
||||
|
||||
public float getFastPlaybackSpeed(boolean music) {
|
||||
return music ? fastMusicPlaybackSpeed : fastPlaybackSpeed;
|
||||
}
|
||||
|
||||
private void updateVideoState(MessageObject messageObject, int[] playCount, boolean destroyAtEnd, boolean playWhenReady, int playbackState) {
|
||||
if (videoPlayer == null) {
|
||||
return;
|
||||
|
@ -3032,9 +3052,14 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
}
|
||||
if (messageObject.isRoundVideo()) {
|
||||
videoPlayer.setStreamType(useFrontSpeaker ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC);
|
||||
if (currentPlaybackSpeed > 1.0f) {
|
||||
if (Math.abs(currentPlaybackSpeed - 1.0f) > 0.001f) {
|
||||
videoPlayer.setPlaybackSpeed(currentPlaybackSpeed);
|
||||
}
|
||||
|
||||
if (messageObject.forceSeekTo >= 0) {
|
||||
messageObject.audioProgress = seekToProgressPending = messageObject.forceSeekTo;
|
||||
messageObject.forceSeekTo = -1;
|
||||
}
|
||||
} else {
|
||||
videoPlayer.setStreamType(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
@ -3053,6 +3078,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
return;
|
||||
}
|
||||
if (playbackState == ExoPlayer.STATE_ENDED || (playbackState == ExoPlayer.STATE_IDLE || playbackState == ExoPlayer.STATE_BUFFERING) && playWhenReady && messageObject.audioProgress >= 0.999f) {
|
||||
messageObject.audioProgress = 1f;
|
||||
NotificationCenter.getInstance(messageObject.currentAccount).postNotificationName(NotificationCenter.messagePlayingProgressDidChanged, messageObject.getId(), 0);
|
||||
if (!playlist.isEmpty() && (playlist.size() > 1 || !messageObject.isVoice())) {
|
||||
playNextMessageWithoutOrder(true);
|
||||
} else {
|
||||
|
@ -3134,7 +3161,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
}
|
||||
shouldSavePositionForCurrentAudio = name;
|
||||
}
|
||||
if (currentPlaybackSpeed > 1.0f) {
|
||||
if (Math.abs(currentPlaybackSpeed - 1.0f) > 0.001f) {
|
||||
audioPlayer.setPlaybackSpeed(currentPlaybackSpeed);
|
||||
}
|
||||
audioInfo = null;
|
||||
|
@ -3153,7 +3180,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener,
|
|||
messageObject.audioProgress = seekToProgressPending = pos;
|
||||
}
|
||||
shouldSavePositionForCurrentAudio = name;
|
||||
if (currentMusicPlaybackSpeed > 1.0f) {
|
||||
if (Math.abs(currentMusicPlaybackSpeed - 1.0f) > 0.001f) {
|
||||
audioPlayer.setPlaybackSpeed(currentMusicPlaybackSpeed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4577,6 +4577,45 @@ public class MediaDataController extends BaseController {
|
|||
return runs;
|
||||
}
|
||||
|
||||
public void addStyle(int flags, int spanStart, int spanEnd, ArrayList<TLRPC.MessageEntity> entities) {
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_BOLD) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityBold();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_ITALIC) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityItalic();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_MONO) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityCode();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_STRIKE) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityStrike();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_UNDERLINE) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityUnderline();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_QUOTE) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityBlockquote();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<TLRPC.MessageEntity> getEntities(CharSequence[] message, boolean allowStrike) {
|
||||
if (message == null || message[0] == null) {
|
||||
return null;
|
||||
|
@ -4671,43 +4710,7 @@ public class MediaDataController extends BaseController {
|
|||
if (entities == null) {
|
||||
entities = new ArrayList<>();
|
||||
}
|
||||
int flags = span.getStyleFlags();
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_BOLD) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityBold();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_ITALIC) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityItalic();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_MONO) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityCode();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_STRIKE) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityStrike();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_UNDERLINE) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityUnderline();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
if ((flags & TextStyleSpan.FLAG_STYLE_QUOTE) != 0) {
|
||||
TLRPC.MessageEntity entity = new TLRPC.TL_messageEntityBlockquote();
|
||||
entity.offset = spanStart;
|
||||
entity.length = spanEnd - spanStart;
|
||||
entities.add(entity);
|
||||
}
|
||||
addStyle(span.getStyleFlags(), spanStart, spanEnd, entities);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4741,6 +4744,10 @@ public class MediaDataController extends BaseController {
|
|||
entity.length = Math.min(spannable.getSpanEnd(spansUrlReplacement[b]), message[0].length()) - entity.offset;
|
||||
entity.url = spansUrlReplacement[b].getURL();
|
||||
entities.add(entity);
|
||||
TextStyleSpan.TextStyleRun style = spansUrlReplacement[b].getTextStyleRun();
|
||||
if (style != null) {
|
||||
addStyle(style.flags, entity.offset, entity.offset + entity.length, entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2984,9 +2984,13 @@ public class MessageObject {
|
|||
} else if (messageOwner.translated) {
|
||||
messageText = messageOwner.translatedMessage;
|
||||
} else {
|
||||
if (messageOwner.message != null && messageOwner.message.length() > 200) {
|
||||
if (messageOwner.message != null) {
|
||||
try {
|
||||
messageText = AndroidUtilities.BAD_CHARS_MESSAGE_PATTERN.matcher(messageOwner.message).replaceAll("\u200C");
|
||||
if (messageOwner.message.length() > 200) {
|
||||
messageText = AndroidUtilities.BAD_CHARS_MESSAGE_LONG_PATTERN.matcher(messageOwner.message).replaceAll("\u200C");
|
||||
} else {
|
||||
messageText = AndroidUtilities.BAD_CHARS_MESSAGE_PATTERN.matcher(messageOwner.message).replaceAll("\u200C");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
messageText = messageOwner.message;
|
||||
}
|
||||
|
|
|
@ -300,6 +300,9 @@ public class MessagesController extends BaseController implements NotificationCe
|
|||
public String mapKey;
|
||||
public int maxMessageLength;
|
||||
public int maxCaptionLength;
|
||||
public int roundVideoSize;
|
||||
public int roundVideoBitrate;
|
||||
public int roundAudioBitrate;
|
||||
public boolean blockedCountry;
|
||||
public boolean preloadFeaturedStickers;
|
||||
public String youtubePipType;
|
||||
|
@ -859,7 +862,9 @@ public class MessagesController extends BaseController implements NotificationCe
|
|||
autoarchiveAvailable = mainPreferences.getBoolean("autoarchiveAvailable", false);
|
||||
groipCallVideoMaxParticipants = mainPreferences.getInt("groipCallVideoMaxParticipants", 30);
|
||||
suggestStickersApiOnly = mainPreferences.getBoolean("suggestStickersApiOnly", false);
|
||||
|
||||
roundVideoSize = mainPreferences.getInt("roundVideoSize", 384);
|
||||
roundVideoBitrate = mainPreferences.getInt("roundVideoBitrate", 1000);
|
||||
roundAudioBitrate = mainPreferences.getInt("roundAudioBitrate", 64);
|
||||
pendingSuggestions = mainPreferences.getStringSet("pendingSuggestions", null);
|
||||
if (pendingSuggestions != null) {
|
||||
pendingSuggestions = new HashSet<>(pendingSuggestions);
|
||||
|
@ -1744,6 +1749,50 @@ public class MessagesController extends BaseController implements NotificationCe
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "round_video_encoding": {
|
||||
if (value.value instanceof TLRPC.TL_jsonObject) {
|
||||
TLRPC.TL_jsonObject jsonObject = (TLRPC.TL_jsonObject) value.value;
|
||||
for (int b = 0, N2 = jsonObject.value.size(); b < N2; b++) {
|
||||
TLRPC.TL_jsonObjectValue value2 = jsonObject.value.get(b);
|
||||
switch (value2.key) {
|
||||
case "diameter": {
|
||||
if (value2.value instanceof TLRPC.TL_jsonNumber) {
|
||||
TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value2.value;
|
||||
if (number.value != roundVideoSize) {
|
||||
roundVideoSize = (int) number.value;
|
||||
editor.putInt("roundVideoSize", roundVideoSize);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "video_bitrate": {
|
||||
if (value2.value instanceof TLRPC.TL_jsonNumber) {
|
||||
TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value2.value;
|
||||
if (number.value != roundVideoBitrate) {
|
||||
roundVideoBitrate = (int) number.value;
|
||||
editor.putInt("roundVideoBitrate", roundVideoBitrate);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "audio_bitrate": {
|
||||
if (value2.value instanceof TLRPC.TL_jsonNumber) {
|
||||
TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value2.value;
|
||||
if (number.value != roundAudioBitrate) {
|
||||
roundAudioBitrate = (int) number.value;
|
||||
editor.putInt("roundAudioBitrate", roundAudioBitrate);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "stickers_emoji_suggest_only_api": {
|
||||
if (value.value instanceof TLRPC.TL_jsonBool) {
|
||||
TLRPC.TL_jsonBool bool = (TLRPC.TL_jsonBool) value.value;
|
||||
|
@ -9679,7 +9728,7 @@ public class MessagesController extends BaseController implements NotificationCe
|
|||
cleanup();
|
||||
getContactsController().deleteUnknownAppAccounts();
|
||||
if (ConnectionsManager.native_isTestBackend(currentAccount) != 0) {
|
||||
ConnectionsManager.native_switchBackend(currentAccount);
|
||||
ConnectionsManager.native_switchBackend(currentAccount, false);
|
||||
}
|
||||
SharedConfig.activeAccounts.remove(currentAccount);
|
||||
SharedConfig.saveAccounts();
|
||||
|
|
|
@ -18,7 +18,7 @@ import tw.nekomimi.nekogram.utils.FileUtil;
|
|||
|
||||
public class NativeLoader {
|
||||
|
||||
private final static int LIB_VERSION = 39;
|
||||
private final static int LIB_VERSION = 40;
|
||||
private final static String LIB_NAME = "tmessages." + LIB_VERSION;
|
||||
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
|
||||
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";
|
||||
|
|
|
@ -492,6 +492,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe
|
|||
public HashMap<String, String> params;
|
||||
public boolean isVideo;
|
||||
public boolean canDeleteAfter;
|
||||
public boolean forceImage;
|
||||
}
|
||||
|
||||
public static class LocationProvider {
|
||||
|
@ -4719,6 +4720,9 @@ public boolean retriedToSend;
|
|||
inputMediaPhoto.id.access_hash = messageMedia.photo.access_hash;
|
||||
inputMediaPhoto.id.file_reference = messageMedia.photo.file_reference;
|
||||
newInputMedia = inputMediaPhoto;
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("set uploaded photo");
|
||||
}
|
||||
} else if (inputMedia instanceof TLRPC.TL_inputMediaUploadedDocument && messageMedia instanceof TLRPC.TL_messageMediaDocument) {
|
||||
TLRPC.TL_inputMediaDocument inputMediaDocument = new TLRPC.TL_inputMediaDocument();
|
||||
inputMediaDocument.id = new TLRPC.TL_inputDocument();
|
||||
|
@ -4726,6 +4730,9 @@ public boolean retriedToSend;
|
|||
inputMediaDocument.id.access_hash = messageMedia.document.access_hash;
|
||||
inputMediaDocument.id.file_reference = messageMedia.document.file_reference;
|
||||
newInputMedia = inputMediaDocument;
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("set uploaded document");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newInputMedia != null) {
|
||||
|
@ -4766,7 +4773,14 @@ public boolean retriedToSend;
|
|||
String key = "group_" + message.groupId;
|
||||
if (message.finalGroupMessage != message.messageObjects.get(message.messageObjects.size() - 1).getId()) {
|
||||
if (add) {
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("final message not added, add");
|
||||
}
|
||||
putToDelayedMessages(key, message);
|
||||
} else {
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("final message not added");
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (add) {
|
||||
|
@ -4776,12 +4790,18 @@ public boolean retriedToSend;
|
|||
if (!message.scheduled) {
|
||||
getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload);
|
||||
}
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("add message");
|
||||
}
|
||||
}
|
||||
if (message.sendRequest instanceof TLRPC.TL_messages_sendMultiMedia) {
|
||||
TLRPC.TL_messages_sendMultiMedia request = (TLRPC.TL_messages_sendMultiMedia) message.sendRequest;
|
||||
for (int a = 0; a < request.multi_media.size(); a++) {
|
||||
TLRPC.InputMedia inputMedia = request.multi_media.get(a).media;
|
||||
if (inputMedia instanceof TLRPC.TL_inputMediaUploadedPhoto || inputMedia instanceof TLRPC.TL_inputMediaUploadedDocument) {
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("multi media not ready");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -4793,6 +4813,9 @@ public boolean retriedToSend;
|
|||
if (message.requests != null) {
|
||||
maxDelayedMessage.requests.addAll(message.requests);
|
||||
}
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("has maxDelayedMessage, delay");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -5721,8 +5744,14 @@ public boolean retriedToSend;
|
|||
getMessagesController().putUsers(users, true);
|
||||
getMessagesController().putChats(chats, true);
|
||||
getMessagesController().putEncryptedChats(encryptedChats, true);
|
||||
for (int a = 0; a < messages.size(); a++) {
|
||||
for (int a = 0, N = messages.size(); a < N; a++) {
|
||||
MessageObject messageObject = new MessageObject(currentAccount, messages.get(a), false, true);
|
||||
long groupId = messageObject.getGroupId();
|
||||
if (groupId != 0 && messageObject.messageOwner.params != null && !messageObject.messageOwner.params.containsKey("final")) {
|
||||
if (a == N - 1 || messages.get(a + 1).grouped_id != groupId) {
|
||||
messageObject.messageOwner.params.put("final", "1");
|
||||
}
|
||||
}
|
||||
retrySendMessage(messageObject, true);
|
||||
}
|
||||
if (scheduledMessages != null) {
|
||||
|
@ -6895,6 +6924,28 @@ public boolean retriedToSend;
|
|||
return String.format(Locale.US, blur ? "%d_%d@%d_%d_b" : "%d_%d@%d_%d", photoSize.location.volume_id, photoSize.location.local_id, (int) (point.x / AndroidUtilities.density), (int) (point.y / AndroidUtilities.density));
|
||||
}
|
||||
|
||||
private static boolean shouldSendWebPAsSticker(String path, Uri uri) {
|
||||
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
||||
bmOptions.inJustDecodeBounds = true;
|
||||
try {
|
||||
if (path != null) {
|
||||
RandomAccessFile file = new RandomAccessFile(path, "r");
|
||||
ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, path.length());
|
||||
Utilities.loadWebpImage(null, buffer, buffer.limit(), bmOptions, true);
|
||||
file.close();
|
||||
} else {
|
||||
try (InputStream inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri)) {
|
||||
BitmapFactory.decodeStream(inputStream, null, bmOptions);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
return bmOptions.outWidth < 800 && bmOptions.outHeight < 800;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public static void prepareSendingMedia(AccountInstance accountInstance, ArrayList<SendingMediaInfo> media, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, InputContentInfoCompat inputContent, boolean forceDocument, boolean groupMedia, MessageObject editingMessageObject, boolean notify, int scheduleDate) {
|
||||
if (media.isEmpty()) {
|
||||
|
@ -6924,13 +6975,22 @@ public boolean retriedToSend;
|
|||
originalPath = info.uri.toString();
|
||||
}
|
||||
|
||||
if (tempPath != null && info.ttl <= 0 && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp"))) {
|
||||
continue;
|
||||
boolean isWebP = false;
|
||||
if (tempPath != null && info.ttl <= 0 && (tempPath.endsWith(".gif") || (isWebP = tempPath.endsWith(".webp")))) {
|
||||
if (!isWebP || shouldSendWebPAsSticker(tempPath, null)) {
|
||||
continue;
|
||||
} else {
|
||||
info.forceImage = true;
|
||||
}
|
||||
} else if (ImageLoader.shouldSendImageAsDocument(info.path, info.uri)) {
|
||||
continue;
|
||||
} else if (tempPath == null && info.uri != null) {
|
||||
if (MediaController.isGif(info.uri) || MediaController.isWebp(info.uri)) {
|
||||
continue;
|
||||
if (MediaController.isGif(info.uri) || (isWebP = MediaController.isWebp(info.uri))) {
|
||||
if (!isWebP || shouldSendWebPAsSticker(null, info.uri)) {
|
||||
continue;
|
||||
} else {
|
||||
info.forceImage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7403,14 +7463,14 @@ public boolean retriedToSend;
|
|||
if (forceDocument || ImageLoader.shouldSendImageAsDocument(info.path, info.uri)) {
|
||||
isDocument = true;
|
||||
extension = tempPath != null ? FileLoader.getFileExtension(new File(tempPath)) : "";
|
||||
} else if (tempPath != null && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp")) && info.ttl <= 0) {
|
||||
} else if (!info.forceImage && tempPath != null && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp")) && info.ttl <= 0) {
|
||||
if (tempPath.endsWith(".gif")) {
|
||||
extension = "gif";
|
||||
} else {
|
||||
extension = "webp";
|
||||
}
|
||||
isDocument = true;
|
||||
} else if (tempPath == null && info.uri != null) {
|
||||
} else if (!info.forceImage && tempPath == null && info.uri != null) {
|
||||
if (MediaController.isGif(info.uri)) {
|
||||
isDocument = true;
|
||||
originalPath = info.uri.toString();
|
||||
|
|
|
@ -1180,7 +1180,7 @@ public class SharedConfig {
|
|||
streamMedia = preferences.getBoolean("streamMedia", true);
|
||||
saveStreamMedia = preferences.getBoolean("saveStreamMedia", true);
|
||||
smoothKeyboard = preferences.getBoolean("smoothKeyboard2", true);
|
||||
pauseMusicOnRecord = preferences.getBoolean("pauseMusicOnRecord", true);
|
||||
pauseMusicOnRecord = preferences.getBoolean("pauseMusicOnRecord", false);
|
||||
streamAllVideo = preferences.getBoolean("streamAllVideo", BuildVars.DEBUG_VERSION);
|
||||
streamMkv = preferences.getBoolean("streamMkv", false);
|
||||
suggestStickers = preferences.getInt("suggestStickers", 0);
|
||||
|
|
|
@ -50,6 +50,9 @@ public class CameraSession {
|
|||
private boolean optimizeForBarcode;
|
||||
private boolean useTorch;
|
||||
private boolean isRound;
|
||||
private boolean destroyed;
|
||||
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
|
||||
public static final int ORIENTATION_HYSTERESIS = 5;
|
||||
|
||||
|
@ -60,6 +63,7 @@ public class CameraSession {
|
|||
|
||||
}
|
||||
};
|
||||
private int displayOrientation;
|
||||
|
||||
public CameraSession(CameraInfo info, Size preview, Size picture, int format, boolean round) {
|
||||
previewSize = preview;
|
||||
|
@ -197,7 +201,6 @@ public class CameraSession {
|
|||
isVideo = true;
|
||||
Camera camera = cameraInfo.camera;
|
||||
if (camera != null) {
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.Parameters params = null;
|
||||
try {
|
||||
params = camera.getParameters();
|
||||
|
@ -206,42 +209,7 @@ public class CameraSession {
|
|||
}
|
||||
|
||||
Camera.getCameraInfo(cameraInfo.getCameraId(), info);
|
||||
|
||||
int displayOrientation = getDisplayOrientation(info, true);
|
||||
int cameraDisplayOrientation;
|
||||
|
||||
if ("samsung".equals(Build.MANUFACTURER) && "sf2wifixx".equals(Build.PRODUCT)) {
|
||||
cameraDisplayOrientation = 0;
|
||||
} else {
|
||||
int degrees = 0;
|
||||
int temp = displayOrientation;
|
||||
switch (temp) {
|
||||
case Surface.ROTATION_0:
|
||||
degrees = 0;
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
degrees = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
degrees = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
degrees = 270;
|
||||
break;
|
||||
}
|
||||
if (info.orientation % 90 != 0) {
|
||||
info.orientation = 0;
|
||||
}
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
temp = (info.orientation + degrees) % 360;
|
||||
temp = (360 - temp) % 360;
|
||||
} else {
|
||||
temp = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
cameraDisplayOrientation = temp;
|
||||
}
|
||||
camera.setDisplayOrientation(currentOrientation = cameraDisplayOrientation);
|
||||
diffOrientation = currentOrientation - displayOrientation;
|
||||
updateRotation();
|
||||
|
||||
if (params != null) {
|
||||
if (initial && BuildVars.LOGS_ENABLED) {
|
||||
|
@ -305,11 +273,71 @@ public class CameraSession {
|
|||
}
|
||||
}
|
||||
|
||||
public void updateRotation() {
|
||||
if (cameraInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Camera.getCameraInfo(cameraInfo.getCameraId(), info);
|
||||
} catch (Throwable throwable) {
|
||||
FileLog.e(throwable);
|
||||
return;
|
||||
}
|
||||
Camera camera = (cameraInfo == null || destroyed) ? null : cameraInfo.camera;
|
||||
|
||||
displayOrientation = getDisplayOrientation(info, true);
|
||||
int cameraDisplayOrientation;
|
||||
|
||||
if ("samsung".equals(Build.MANUFACTURER) && "sf2wifixx".equals(Build.PRODUCT)) {
|
||||
cameraDisplayOrientation = 0;
|
||||
} else {
|
||||
int degrees = 0;
|
||||
int temp = displayOrientation;
|
||||
switch (temp) {
|
||||
case Surface.ROTATION_0:
|
||||
degrees = 0;
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
degrees = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
degrees = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
degrees = 270;
|
||||
break;
|
||||
}
|
||||
if (info.orientation % 90 != 0) {
|
||||
info.orientation = 0;
|
||||
}
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
temp = (info.orientation + degrees) % 360;
|
||||
temp = (360 - temp) % 360;
|
||||
} else {
|
||||
temp = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
cameraDisplayOrientation = temp;
|
||||
}
|
||||
currentOrientation = cameraDisplayOrientation;
|
||||
if (camera != null) {
|
||||
try {
|
||||
camera.setDisplayOrientation(currentOrientation);
|
||||
} catch (Throwable ignore) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
diffOrientation = currentOrientation - displayOrientation;
|
||||
if (diffOrientation < 0) {
|
||||
diffOrientation += 360;
|
||||
}
|
||||
}
|
||||
|
||||
protected void configurePhotoCamera() {
|
||||
try {
|
||||
Camera camera = cameraInfo.camera;
|
||||
if (camera != null) {
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.Parameters params = null;
|
||||
try {
|
||||
params = camera.getParameters();
|
||||
|
@ -319,41 +347,12 @@ public class CameraSession {
|
|||
|
||||
Camera.getCameraInfo(cameraInfo.getCameraId(), info);
|
||||
|
||||
int displayOrientation = getDisplayOrientation(info, true);
|
||||
int cameraDisplayOrientation;
|
||||
updateRotation();
|
||||
|
||||
if ("samsung".equals(Build.MANUFACTURER) && "sf2wifixx".equals(Build.PRODUCT)) {
|
||||
cameraDisplayOrientation = 0;
|
||||
} else {
|
||||
int degrees = 0;
|
||||
int temp = displayOrientation;
|
||||
switch (temp) {
|
||||
case Surface.ROTATION_0:
|
||||
degrees = 0;
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
degrees = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
degrees = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
degrees = 270;
|
||||
break;
|
||||
}
|
||||
if (info.orientation % 90 != 0) {
|
||||
info.orientation = 0;
|
||||
}
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
temp = (info.orientation + degrees) % 360;
|
||||
temp = (360 - temp) % 360;
|
||||
} else {
|
||||
temp = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
cameraDisplayOrientation = temp;
|
||||
}
|
||||
camera.setDisplayOrientation(currentOrientation = cameraDisplayOrientation);
|
||||
diffOrientation = currentOrientation - displayOrientation;
|
||||
if (diffOrientation < 0) {
|
||||
diffOrientation += 360;
|
||||
}
|
||||
|
||||
if (params != null) {
|
||||
params.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
|
||||
|
@ -470,10 +469,7 @@ public class CameraSession {
|
|||
}
|
||||
|
||||
protected void configureRecorder(int quality, MediaRecorder recorder) {
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraInfo.cameraId, info);
|
||||
int displayOrientation = getDisplayOrientation(info, false);
|
||||
|
||||
|
||||
int outputOrientation = 0;
|
||||
if (jpegOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
|
||||
|
@ -552,7 +548,6 @@ public class CameraSession {
|
|||
|
||||
public int getDisplayOrientation() {
|
||||
try {
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraInfo.getCameraId(), info);
|
||||
return getDisplayOrientation(info, true);
|
||||
} catch (Exception e) {
|
||||
|
@ -577,6 +572,7 @@ public class CameraSession {
|
|||
|
||||
public void destroy() {
|
||||
initied = false;
|
||||
destroyed = true;
|
||||
if (orientationEventListener != null) {
|
||||
orientationEventListener.disable();
|
||||
orientationEventListener = null;
|
||||
|
|
|
@ -53,6 +53,8 @@ import android.widget.ImageView;
|
|||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.DispatchQueue;
|
||||
|
@ -277,6 +279,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
|
|||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (previewSize != null && cameraSession != null) {
|
||||
int frameWidth, frameHeight;
|
||||
cameraSession.updateRotation();
|
||||
if (cameraSession.getWorldAngle() == 90 || cameraSession.getWorldAngle() == 270) {
|
||||
frameWidth = previewSize.getWidth();
|
||||
frameHeight = previewSize.getHeight();
|
||||
|
@ -289,6 +292,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
|
|||
blurredStubView.getLayoutParams().height = textureView.getLayoutParams().height = (int) (s * frameHeight);
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
checkPreviewMatrix();
|
||||
}
|
||||
|
||||
public float getTextureHeight(float width, float height) {
|
||||
|
@ -490,7 +494,8 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
|
|||
|
||||
if (cameraThread != null) {
|
||||
cameraThread.postRunnable(() -> {
|
||||
if (cameraThread.currentSession != null) {
|
||||
final CameraGLThread cameraThread = this.cameraThread;
|
||||
if (cameraThread != null && cameraThread.currentSession != null) {
|
||||
int rotationAngle = cameraThread.currentSession.getWorldAngle();
|
||||
android.opengl.Matrix.setIdentityM(mMVPMatrix, 0);
|
||||
if (rotationAngle != 0) {
|
||||
|
@ -1035,16 +1040,16 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
|
|||
FileLog.d("CameraView " + "set gl rednderer session");
|
||||
}
|
||||
CameraSession newSession = (CameraSession) inputMessage.obj;
|
||||
if (currentSession == newSession) {
|
||||
int rotationAngle = currentSession.getWorldAngle();
|
||||
android.opengl.Matrix.setIdentityM(mMVPMatrix, 0);
|
||||
if (rotationAngle != 0) {
|
||||
android.opengl.Matrix.rotateM(mMVPMatrix, 0, rotationAngle, 0, 0, 1);
|
||||
}
|
||||
} else {
|
||||
if (currentSession != newSession) {
|
||||
currentSession = newSession;
|
||||
cameraId = newSession.cameraInfo.cameraId;
|
||||
}
|
||||
currentSession.updateRotation();
|
||||
int rotationAngle = currentSession.getWorldAngle();
|
||||
android.opengl.Matrix.setIdentityM(mMVPMatrix, 0);
|
||||
if (rotationAngle != 0) {
|
||||
android.opengl.Matrix.rotateM(mMVPMatrix, 0, rotationAngle, 0, 0, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DO_START_RECORDING: {
|
||||
|
@ -1153,6 +1158,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
|
|||
FileLog.d("CameraView " + "camera initied");
|
||||
}
|
||||
cameraSession.setInitied();
|
||||
requestLayout();
|
||||
}
|
||||
}, () -> cameraThread.setCurrentSession(cameraSession));
|
||||
});
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
package org.telegram.messenger.video;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.ui.Components.VideoForwardDrawable;
|
||||
import org.telegram.ui.Components.VideoPlayer;
|
||||
|
||||
public class VideoPlayerRewinder {
|
||||
|
||||
public int rewindCount;
|
||||
private boolean rewindForward;
|
||||
public boolean rewindByBackSeek;
|
||||
private long startRewindFrom;
|
||||
private Runnable updateRewindRunnable;
|
||||
private long rewindLastTime;
|
||||
private long rewindLastUpdatePlayerTime;
|
||||
private long rewindBackSeekPlayerPosition;
|
||||
private float playSpeed = 1f;
|
||||
|
||||
private VideoPlayer videoPlayer;
|
||||
|
||||
private final Runnable backSeek = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (videoPlayer == null) {
|
||||
return;
|
||||
}
|
||||
long duration = videoPlayer.getDuration();
|
||||
if (duration == 0 || duration == C.TIME_UNSET) {
|
||||
rewindLastTime = System.currentTimeMillis();
|
||||
return;
|
||||
}
|
||||
|
||||
long t = System.currentTimeMillis();
|
||||
long dt = t - rewindLastTime;
|
||||
rewindLastTime = t;
|
||||
if (rewindCount == 1) {
|
||||
dt *= 3;
|
||||
} else if (rewindCount == 2) {
|
||||
dt *= 6;
|
||||
} else {
|
||||
dt *= 12;
|
||||
}
|
||||
if (rewindForward) {
|
||||
rewindBackSeekPlayerPosition += dt;
|
||||
} else {
|
||||
rewindBackSeekPlayerPosition -= dt;
|
||||
}
|
||||
if (rewindBackSeekPlayerPosition < 0) {
|
||||
rewindBackSeekPlayerPosition = 0;
|
||||
} else if (rewindBackSeekPlayerPosition > duration) {
|
||||
rewindBackSeekPlayerPosition = duration;
|
||||
}
|
||||
if (rewindByBackSeek && videoPlayer != null && rewindLastTime - rewindLastUpdatePlayerTime > 350) {
|
||||
rewindLastUpdatePlayerTime = rewindLastTime;
|
||||
videoPlayer.seekTo(rewindBackSeekPlayerPosition);
|
||||
}
|
||||
|
||||
if (videoPlayer != null) {
|
||||
long timeDiff = rewindBackSeekPlayerPosition - startRewindFrom;
|
||||
float progress = rewindBackSeekPlayerPosition / (float) videoPlayer.getDuration();
|
||||
updateRewindProgressUi(timeDiff, progress, rewindByBackSeek);
|
||||
}
|
||||
|
||||
if (rewindBackSeekPlayerPosition == 0 || rewindBackSeekPlayerPosition >= duration) {
|
||||
if (rewindByBackSeek && videoPlayer != null) {
|
||||
rewindLastUpdatePlayerTime = rewindLastTime;
|
||||
videoPlayer.seekTo(rewindBackSeekPlayerPosition);
|
||||
}
|
||||
cancelRewind();
|
||||
}
|
||||
if (rewindCount > 0) {
|
||||
AndroidUtilities.runOnUIThread(backSeek, 16);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void startRewind(VideoPlayer videoPlayer, boolean forward, float playbackSpeed) {
|
||||
this.videoPlayer = videoPlayer;
|
||||
this.playSpeed = playbackSpeed;
|
||||
rewindForward = forward;
|
||||
cancelRewind();
|
||||
incrementRewindCount();
|
||||
}
|
||||
|
||||
public void cancelRewind() {
|
||||
if (rewindCount != 0) {
|
||||
rewindCount = 0;
|
||||
|
||||
if (videoPlayer != null) {
|
||||
if (rewindByBackSeek) {
|
||||
videoPlayer.seekTo(rewindBackSeekPlayerPosition);
|
||||
} else {
|
||||
long current = videoPlayer.getCurrentPosition();
|
||||
videoPlayer.seekTo(current);
|
||||
}
|
||||
videoPlayer.setPlaybackSpeed(playSpeed);
|
||||
}
|
||||
}
|
||||
AndroidUtilities.cancelRunOnUIThread(backSeek);
|
||||
|
||||
if (updateRewindRunnable != null) {
|
||||
AndroidUtilities.cancelRunOnUIThread(updateRewindRunnable);
|
||||
updateRewindRunnable = null;
|
||||
}
|
||||
|
||||
onRewindCanceled();
|
||||
}
|
||||
|
||||
private void incrementRewindCount() {
|
||||
if (videoPlayer == null) {
|
||||
return;
|
||||
}
|
||||
rewindCount++;
|
||||
boolean needUpdate = false;
|
||||
if (rewindCount == 1) {
|
||||
if (rewindForward && videoPlayer.isPlaying()) {
|
||||
rewindByBackSeek = false;
|
||||
} else {
|
||||
rewindByBackSeek = true;
|
||||
}
|
||||
}
|
||||
if (rewindForward && !rewindByBackSeek) {
|
||||
if (rewindCount == 1) {
|
||||
videoPlayer.setPlaybackSpeed(4);
|
||||
needUpdate = true;
|
||||
} else if (rewindCount == 2) {
|
||||
videoPlayer.setPlaybackSpeed(7);
|
||||
needUpdate = true;
|
||||
} else {
|
||||
videoPlayer.setPlaybackSpeed(13);
|
||||
}
|
||||
} else {
|
||||
if (rewindCount == 1 || rewindCount == 2) {
|
||||
needUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rewindCount == 1) {
|
||||
rewindBackSeekPlayerPosition = videoPlayer.getCurrentPosition();
|
||||
rewindLastTime = System.currentTimeMillis();
|
||||
rewindLastUpdatePlayerTime = rewindLastTime;
|
||||
startRewindFrom = videoPlayer.getCurrentPosition();
|
||||
onRewindStart(rewindForward);
|
||||
}
|
||||
|
||||
AndroidUtilities.cancelRunOnUIThread(backSeek);
|
||||
AndroidUtilities.runOnUIThread(backSeek);
|
||||
|
||||
if (needUpdate) {
|
||||
if (updateRewindRunnable != null) {
|
||||
AndroidUtilities.cancelRunOnUIThread(updateRewindRunnable);
|
||||
}
|
||||
AndroidUtilities.runOnUIThread(updateRewindRunnable = () -> {
|
||||
updateRewindRunnable = null;
|
||||
incrementRewindCount();
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void updateRewindProgressUi(long timeDiff, float progress, boolean rewindByBackSeek) {
|
||||
|
||||
}
|
||||
|
||||
protected void onRewindStart(boolean rewindForward) {
|
||||
|
||||
}
|
||||
|
||||
protected void onRewindCanceled() {
|
||||
|
||||
}
|
||||
|
||||
public float getVideoProgress() {
|
||||
return rewindBackSeekPlayerPosition / (float) videoPlayer.getDuration();
|
||||
}
|
||||
}
|
|
@ -198,6 +198,7 @@ public class NativeInstance {
|
|||
public native void onMediaDescriptionAvailable(long taskPtr, int[] ssrcs);
|
||||
public native void setNoiseSuppressionEnabled(boolean value);
|
||||
public native void activateVideoCapturer(long videoCapturer);
|
||||
public native void clearVideoCapturer();
|
||||
public native long addIncomingVideoOutput(int quality, String endpointId, SsrcGroup[] ssrcGroups, VideoSink remoteSink);
|
||||
public native void removeIncomingVideoOutput(long nativeRemoteSink);
|
||||
public native void setVideoEndpointQuality(String endpointId, int quality);
|
||||
|
@ -216,7 +217,7 @@ public class NativeInstance {
|
|||
public native byte[] getPersistentState();
|
||||
private native void stopNative();
|
||||
private native void stopGroupNative();
|
||||
public native void setupOutgoingVideo(VideoSink localSink, boolean front);
|
||||
public native void setupOutgoingVideo(VideoSink localSink, int type);
|
||||
public native void setupOutgoingVideoCreated(long videoCapturer);
|
||||
public native void switchCamera(boolean front);
|
||||
public native void setVideoState(int videoState);
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.webrtc.Logging;
|
|||
import org.webrtc.ScreenCapturerAndroid;
|
||||
import org.webrtc.SurfaceTextureHelper;
|
||||
import org.webrtc.VideoCapturer;
|
||||
import org.webrtc.voiceengine.WebRtcAudioRecord;
|
||||
|
||||
@TargetApi(18)
|
||||
public class VideoCapturerDevice {
|
||||
|
@ -165,6 +166,10 @@ public class VideoCapturerDevice {
|
|||
nativeCapturerObserver = nativeGetJavaVideoCapturerObserver(nativePtr);
|
||||
videoCapturer.initialize(videoCapturerSurfaceTextureHelper, ApplicationLoader.applicationContext, nativeCapturerObserver);
|
||||
videoCapturer.startCapture(size.x, size.y, CAPTURE_FPS);
|
||||
WebRtcAudioRecord audioRecord = WebRtcAudioRecord.Instance;
|
||||
if (audioRecord != null) {
|
||||
audioRecord.initDeviceAudioRecord(((ScreenCapturerAndroid) videoCapturer).getMediaProjection());
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
@ -183,7 +188,41 @@ public class VideoCapturerDevice {
|
|||
}
|
||||
String cameraName = names[index];
|
||||
if (videoCapturer == null) {
|
||||
videoCapturer = enumerator.createCapturer(cameraName, null);
|
||||
videoCapturer = enumerator.createCapturer(cameraName, new CameraVideoCapturer.CameraEventsHandler() {
|
||||
@Override
|
||||
public void onCameraError(String errorDescription) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraDisconnected() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraFreezed(String errorDescription) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraOpening(String cameraName) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFirstFrameAvailable() {
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
if (VoIPService.getSharedInstance() != null) {
|
||||
VoIPService.getSharedInstance().onCameraFirstFrameAvailable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraClosed() {
|
||||
|
||||
}
|
||||
});
|
||||
videoCapturerSurfaceTextureHelper = SurfaceTextureHelper.create("VideoCapturerThread", eglBase.getEglBaseContext());
|
||||
handler.post(() -> {
|
||||
if (videoCapturerSurfaceTextureHelper == null) {
|
||||
|
@ -288,6 +327,12 @@ public class VideoCapturerDevice {
|
|||
}
|
||||
}
|
||||
handler.post(() -> {
|
||||
if (videoCapturer instanceof ScreenCapturerAndroid) {
|
||||
WebRtcAudioRecord audioRecord = WebRtcAudioRecord.Instance;
|
||||
if (audioRecord != null) {
|
||||
audioRecord.stopDeviceAudioRecord();
|
||||
}
|
||||
}
|
||||
if (videoCapturer != null) {
|
||||
try {
|
||||
videoCapturer.stopCapture();
|
||||
|
|
|
@ -114,6 +114,7 @@ import org.telegram.ui.Components.JoinCallAlert;
|
|||
import org.telegram.ui.Components.voip.VoIPHelper;
|
||||
import org.telegram.ui.LaunchActivity;
|
||||
import org.telegram.ui.VoIPFeedbackActivity;
|
||||
import org.telegram.ui.VoIPFragment;
|
||||
import org.telegram.ui.VoIPPermissionActivity;
|
||||
import org.webrtc.VideoFrame;
|
||||
import org.webrtc.VideoSink;
|
||||
|
@ -196,6 +197,7 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
private boolean notificationsDisabled;
|
||||
private boolean switchingCamera;
|
||||
private boolean isFrontFaceCamera = true;
|
||||
private boolean isPrivateScreencast;
|
||||
private String lastError;
|
||||
private PowerManager.WakeLock proximityWakelock;
|
||||
private PowerManager.WakeLock cpuWakelock;
|
||||
|
@ -448,6 +450,10 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
return isFrontFaceCamera;
|
||||
}
|
||||
|
||||
public boolean isScreencast() {
|
||||
return isPrivateScreencast;
|
||||
}
|
||||
|
||||
public void setMicMute(boolean mute, boolean hold, boolean send) {
|
||||
if (micMute == mute || micSwitching) {
|
||||
return;
|
||||
|
@ -1054,11 +1060,17 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
return currentState != STATE_WAIT_INIT && currentState != STATE_CREATING;
|
||||
}
|
||||
|
||||
public void requestVideoCall() {
|
||||
public void requestVideoCall(boolean screencast) {
|
||||
if (tgVoip[CAPTURE_DEVICE_CAMERA] == null) {
|
||||
return;
|
||||
}
|
||||
tgVoip[CAPTURE_DEVICE_CAMERA].setupOutgoingVideo(localSink[CAPTURE_DEVICE_CAMERA], isFrontFaceCamera);
|
||||
if (!screencast && captureDevice[CAPTURE_DEVICE_CAMERA] != 0) {
|
||||
tgVoip[CAPTURE_DEVICE_CAMERA].setupOutgoingVideoCreated(captureDevice[CAPTURE_DEVICE_CAMERA]);
|
||||
destroyCaptureDevice[CAPTURE_DEVICE_CAMERA] = false;
|
||||
} else {
|
||||
tgVoip[CAPTURE_DEVICE_CAMERA].setupOutgoingVideo(localSink[CAPTURE_DEVICE_CAMERA], screencast ? 2 : (isFrontFaceCamera ? 1 : 0));
|
||||
}
|
||||
isPrivateScreencast = screencast;
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
|
@ -1080,63 +1092,91 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
} else {
|
||||
deviceType = isFrontFaceCamera ? 1 : 0;
|
||||
}
|
||||
if (index == CAPTURE_DEVICE_SCREEN) {
|
||||
if (captureDevice[index] != 0) {
|
||||
return;
|
||||
if (groupCall == null) {
|
||||
if (!isPrivateScreencast && screencast) {
|
||||
setVideoState(false, Instance.VIDEO_STATE_INACTIVE);
|
||||
}
|
||||
isPrivateScreencast = screencast;
|
||||
if (tgVoip[CAPTURE_DEVICE_CAMERA] != null) {
|
||||
tgVoip[CAPTURE_DEVICE_CAMERA].clearVideoCapturer();
|
||||
}
|
||||
}
|
||||
if (index == CAPTURE_DEVICE_SCREEN) {
|
||||
if (groupCall != null) {
|
||||
if (captureDevice[index] != 0) {
|
||||
return;
|
||||
}
|
||||
captureDevice[index] = NativeInstance.createVideoCapturer(localSink[index], deviceType);
|
||||
createGroupInstance(CAPTURE_DEVICE_SCREEN, false);
|
||||
setVideoState(true, Instance.VIDEO_STATE_ACTIVE);
|
||||
AccountInstance.getInstance(currentAccount).getNotificationCenter().postNotificationName(NotificationCenter.groupCallScreencastStateChanged);
|
||||
} else {
|
||||
requestVideoCall(true);
|
||||
setVideoState(true, Instance.VIDEO_STATE_ACTIVE);
|
||||
if (VoIPFragment.getInstance() != null) {
|
||||
VoIPFragment.getInstance().onScreenCastStart();
|
||||
}
|
||||
}
|
||||
captureDevice[index] = NativeInstance.createVideoCapturer(localSink[index], deviceType);
|
||||
createGroupInstance(CAPTURE_DEVICE_SCREEN, false);
|
||||
setVideoState(true, Instance.VIDEO_STATE_ACTIVE);
|
||||
AccountInstance.getInstance(currentAccount).getNotificationCenter().postNotificationName(NotificationCenter.groupCallScreencastStateChanged);
|
||||
} else {
|
||||
if (captureDevice[index] != 0 || tgVoip[index] == null) {
|
||||
if (tgVoip[index] != null && captureDevice[index] != 0) {
|
||||
tgVoip[index].activateVideoCapturer(captureDevice[index]);
|
||||
}
|
||||
return;
|
||||
if (captureDevice[index] != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
captureDevice[index] = NativeInstance.createVideoCapturer(localSink[index], deviceType);
|
||||
}
|
||||
}
|
||||
|
||||
public void setupCaptureDevice(boolean screencast, boolean micEnabled) {
|
||||
int index = screencast ? CAPTURE_DEVICE_SCREEN : CAPTURE_DEVICE_CAMERA;
|
||||
if (captureDevice[index] == 0 || tgVoip[index] == null) {
|
||||
return;
|
||||
if (!screencast) {
|
||||
int index = screencast ? CAPTURE_DEVICE_SCREEN : CAPTURE_DEVICE_CAMERA;
|
||||
if (captureDevice[index] == 0 || tgVoip[index] == null) {
|
||||
return;
|
||||
}
|
||||
tgVoip[index].setupOutgoingVideoCreated(captureDevice[index]);
|
||||
destroyCaptureDevice[index] = false;
|
||||
videoState[index] = Instance.VIDEO_STATE_ACTIVE;
|
||||
}
|
||||
tgVoip[index].setupOutgoingVideoCreated(captureDevice[index]);
|
||||
destroyCaptureDevice[index] = false;
|
||||
videoState[index] = Instance.VIDEO_STATE_ACTIVE;
|
||||
if (micMute == micEnabled) {
|
||||
setMicMute(!micEnabled, false, false);
|
||||
micSwitching = true;
|
||||
}
|
||||
if (!screencast && groupCall != null) {
|
||||
editCallMember(UserConfig.getInstance(currentAccount).getCurrentUser(), !micEnabled, videoState[index] != Instance.VIDEO_STATE_ACTIVE, null, null, () -> micSwitching = false);
|
||||
if (groupCall != null) {
|
||||
editCallMember(UserConfig.getInstance(currentAccount).getCurrentUser(), !micEnabled, videoState[CAPTURE_DEVICE_CAMERA] != Instance.VIDEO_STATE_ACTIVE, null, null, () -> micSwitching = false);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearCamera() {
|
||||
if (tgVoip[CAPTURE_DEVICE_CAMERA] != null) {
|
||||
tgVoip[CAPTURE_DEVICE_CAMERA].clearVideoCapturer();
|
||||
}
|
||||
}
|
||||
|
||||
public void setVideoState(boolean screencast, int state) {
|
||||
int index = screencast ? CAPTURE_DEVICE_SCREEN : CAPTURE_DEVICE_CAMERA;
|
||||
if (tgVoip[index] == null) {
|
||||
int trueIndex = groupCall != null ? index : CAPTURE_DEVICE_CAMERA;
|
||||
if (tgVoip[trueIndex] == null) {
|
||||
if (captureDevice[index] != 0) {
|
||||
videoState[index] = state;
|
||||
NativeInstance.setVideoStateCapturer(captureDevice[index], videoState[index]);
|
||||
videoState[trueIndex] = state;
|
||||
NativeInstance.setVideoStateCapturer(captureDevice[index], videoState[trueIndex]);
|
||||
} else if (state == Instance.VIDEO_STATE_ACTIVE && currentState != STATE_BUSY && currentState != STATE_ENDED) {
|
||||
captureDevice[index] = NativeInstance.createVideoCapturer(localSink[index], isFrontFaceCamera ? 1 : 0);
|
||||
videoState[index] = Instance.VIDEO_STATE_ACTIVE;
|
||||
captureDevice[index] = NativeInstance.createVideoCapturer(localSink[trueIndex], isFrontFaceCamera ? 1 : 0);
|
||||
videoState[trueIndex] = Instance.VIDEO_STATE_ACTIVE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
videoState[index] = state;
|
||||
tgVoip[index].setVideoState(videoState[index]);
|
||||
videoState[trueIndex] = state;
|
||||
tgVoip[trueIndex].setVideoState(videoState[trueIndex]);
|
||||
if (captureDevice[index] != 0) {
|
||||
NativeInstance.setVideoStateCapturer(captureDevice[index], videoState[index]);
|
||||
}
|
||||
if (!screencast && groupCall != null) {
|
||||
editCallMember(UserConfig.getInstance(currentAccount).getCurrentUser(), null, videoState[CAPTURE_DEVICE_CAMERA] != Instance.VIDEO_STATE_ACTIVE, null, null, null);
|
||||
NativeInstance.setVideoStateCapturer(captureDevice[index], videoState[trueIndex]);
|
||||
}
|
||||
if (!screencast) {
|
||||
if (groupCall != null) {
|
||||
editCallMember(UserConfig.getInstance(currentAccount).getCurrentUser(), null, videoState[CAPTURE_DEVICE_CAMERA] != Instance.VIDEO_STATE_ACTIVE, null, null, null);
|
||||
}
|
||||
checkIsNear();
|
||||
}
|
||||
}
|
||||
|
@ -2485,6 +2525,13 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
}
|
||||
}
|
||||
|
||||
protected void onCameraFirstFrameAvailable() {
|
||||
for (int a = 0; a < stateListeners.size(); a++) {
|
||||
StateListener l = stateListeners.get(a);
|
||||
l.onCameraFirstFrameAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerStateListener(StateListener l) {
|
||||
if (stateListeners.contains(l)) {
|
||||
return;
|
||||
|
@ -2856,10 +2903,12 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
}
|
||||
stopForeground(true);
|
||||
stopRinging();
|
||||
if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn) {
|
||||
MessagesController.getInstance(currentAccount).ignoreSetOnline = false;
|
||||
if (currentAccount >= 0) {
|
||||
if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn) {
|
||||
MessagesController.getInstance(currentAccount).ignoreSetOnline = false;
|
||||
}
|
||||
NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.appDidLogout);
|
||||
}
|
||||
NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.appDidLogout);
|
||||
SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
|
||||
Sensor proximity = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
||||
if (proximity != null) {
|
||||
|
@ -2963,15 +3012,17 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
}
|
||||
}
|
||||
|
||||
ConnectionsManager.getInstance(currentAccount).setAppPaused(true, false);
|
||||
VoIPHelper.lastCallTime = SystemClock.elapsedRealtime();
|
||||
|
||||
setSinks(null, null);
|
||||
if (onDestroyRunnable != null) {
|
||||
onDestroyRunnable.run();
|
||||
}
|
||||
if (ChatObject.isChannel(chat)) {
|
||||
MessagesController.getInstance(currentAccount).startShortPoll(chat, classGuid, true);
|
||||
if (currentAccount >= 0) {
|
||||
ConnectionsManager.getInstance(currentAccount).setAppPaused(true, false);
|
||||
if (ChatObject.isChannel(chat)) {
|
||||
MessagesController.getInstance(currentAccount).startShortPoll(chat, classGuid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4229,6 +4280,10 @@ public class VoIPService extends Service implements SensorEventListener, AudioMa
|
|||
|
||||
}
|
||||
|
||||
default void onCameraFirstFrameAvailable() {
|
||||
|
||||
}
|
||||
|
||||
default void onVideoAvailableChange(boolean isAvailable) {
|
||||
|
||||
}
|
||||
|
|
|
@ -430,10 +430,14 @@ public class ConnectionsManager extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
public void switchBackend() {
|
||||
public void switchBackend(boolean restart) {
|
||||
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
|
||||
preferences.edit().remove("language_showed2").apply();
|
||||
native_switchBackend(currentAccount);
|
||||
native_switchBackend(currentAccount, restart);
|
||||
}
|
||||
|
||||
public boolean isTestBackend() {
|
||||
return native_isTestBackend(currentAccount) != 0;
|
||||
}
|
||||
|
||||
public void resumeNetworkMaybe() {
|
||||
|
@ -715,8 +719,7 @@ public class ConnectionsManager extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
public static native void native_switchBackend(int currentAccount);
|
||||
|
||||
public static native void native_switchBackend(int currentAccount, boolean restart);
|
||||
public static native int native_isTestBackend(int currentAccount);
|
||||
|
||||
public static native void native_pauseNetwork(int currentAccount);
|
||||
|
|
|
@ -25,6 +25,11 @@ import android.os.Build;
|
|||
import android.text.SpannableString;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.transition.ChangeBounds;
|
||||
import android.transition.Fade;
|
||||
import android.transition.TransitionManager;
|
||||
import android.transition.TransitionSet;
|
||||
import android.transition.TransitionValues;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
@ -33,11 +38,13 @@ import android.view.ViewPropertyAnimator;
|
|||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.SharedConfig;
|
||||
import org.telegram.ui.Adapters.FiltersView;
|
||||
import org.telegram.ui.Components.CubicBezierInterpolator;
|
||||
import org.telegram.ui.Components.EllipsizeSpanAnimator;
|
||||
import org.telegram.ui.Components.FireworksEffect;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
|
@ -112,6 +119,8 @@ public class ActionBar extends FrameLayout {
|
|||
private boolean overlayTitleAnimation;
|
||||
private boolean titleAnimationRunning;
|
||||
private boolean fromBottom;
|
||||
private boolean centerScale;
|
||||
private CharSequence subtitle;
|
||||
|
||||
EllipsizeSpanAnimator ellipsizeSpanAnimator = new EllipsizeSpanAnimator(this);
|
||||
|
||||
|
@ -330,9 +339,13 @@ public class ActionBar extends FrameLayout {
|
|||
createSubtitleTextView();
|
||||
}
|
||||
if (subtitleTextView != null) {
|
||||
subtitleTextView.setVisibility(!TextUtils.isEmpty(value) && !isSearchFieldVisible ? VISIBLE : GONE);
|
||||
boolean isEmpty = TextUtils.isEmpty(value);
|
||||
subtitleTextView.setVisibility(!isEmpty && !isSearchFieldVisible ? VISIBLE : GONE);
|
||||
subtitleTextView.setAlpha(1f);
|
||||
subtitleTextView.setText(value);
|
||||
if (!isEmpty) {
|
||||
subtitleTextView.setText(value);
|
||||
}
|
||||
subtitle = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,10 +442,10 @@ public class ActionBar extends FrameLayout {
|
|||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
if (subtitleTextView == null) {
|
||||
if (subtitleTextView == null || subtitle == null) {
|
||||
return null;
|
||||
}
|
||||
return subtitleTextView.getText().toString();
|
||||
return subtitle.toString();
|
||||
}
|
||||
|
||||
public ActionBarMenu createMenu() {
|
||||
|
@ -576,7 +589,7 @@ public class ActionBar extends FrameLayout {
|
|||
if (titleTextView[0] != null) {
|
||||
titleTextView[0].setVisibility(INVISIBLE);
|
||||
}
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitleTextView.getText())) {
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitle)) {
|
||||
subtitleTextView.setVisibility(INVISIBLE);
|
||||
}
|
||||
if (menu != null) {
|
||||
|
@ -645,7 +658,7 @@ public class ActionBar extends FrameLayout {
|
|||
if (titleTextView[0] != null) {
|
||||
titleTextView[0].setVisibility(INVISIBLE);
|
||||
}
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitleTextView.getText())) {
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitle)) {
|
||||
subtitleTextView.setVisibility(INVISIBLE);
|
||||
}
|
||||
if (menu != null) {
|
||||
|
@ -736,7 +749,7 @@ public class ActionBar extends FrameLayout {
|
|||
if (titleTextView[0] != null) {
|
||||
titleTextView[0].setVisibility(VISIBLE);
|
||||
}
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitleTextView.getText())) {
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitle)) {
|
||||
subtitleTextView.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
@ -820,7 +833,7 @@ public class ActionBar extends FrameLayout {
|
|||
viewsToHide.add(titleTextView[0]);
|
||||
}
|
||||
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitleTextView.getText())) {
|
||||
if (subtitleTextView != null && !TextUtils.isEmpty(subtitle)) {
|
||||
viewsToHide.add(subtitleTextView);
|
||||
subtitleTextView.setVisibility(visible ? INVISIBLE : VISIBLE);
|
||||
}
|
||||
|
@ -837,7 +850,8 @@ public class ActionBar extends FrameLayout {
|
|||
searchVisibleAnimator.playTogether(ObjectAnimator.ofFloat(view, View.SCALE_Y, visible ? 0.95f : 1f));
|
||||
searchVisibleAnimator.playTogether(ObjectAnimator.ofFloat(view, View.SCALE_X, visible ? 0.95f : 1f));
|
||||
}
|
||||
|
||||
centerScale = true;
|
||||
requestLayout();
|
||||
searchVisibleAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
|
@ -1015,10 +1029,15 @@ public class ActionBar extends FrameLayout {
|
|||
}
|
||||
|
||||
if (titleTextView[i] != null && titleTextView[i].getVisibility() != GONE) {
|
||||
CharSequence text = titleTextView[i].getText();
|
||||
titleTextView[i].setPivotX(titleTextView[i].getTextPaint().measureText(text, 0, text.length()) / 2f);
|
||||
titleTextView[i].setPivotY((AndroidUtilities.dp(24) >> 1));
|
||||
titleTextView[i].measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.AT_MOST));
|
||||
if (centerScale) {
|
||||
CharSequence text = titleTextView[i].getText();
|
||||
titleTextView[i].setPivotX(titleTextView[i].getTextPaint().measureText(text, 0, text.length()) / 2f);
|
||||
titleTextView[i].setPivotY((AndroidUtilities.dp(24) >> 1));
|
||||
} else {
|
||||
titleTextView[i].setPivotX(0);
|
||||
titleTextView[i].setPivotY(0);
|
||||
}
|
||||
}
|
||||
if (subtitleTextView != null && subtitleTextView.getVisibility() != GONE) {
|
||||
subtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST));
|
||||
|
@ -1222,6 +1241,8 @@ public class ActionBar extends FrameLayout {
|
|||
} else {
|
||||
animator.scaleY(0.7f).scaleX(0.7f);
|
||||
}
|
||||
requestLayout();
|
||||
centerScale = true;
|
||||
animator.setDuration(220).setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
|
@ -1335,7 +1356,7 @@ public class ActionBar extends FrameLayout {
|
|||
setTitle(title);
|
||||
return;
|
||||
}
|
||||
boolean crossfade = overlayTitleAnimation && !TextUtils.isEmpty(subtitleTextView.getText());
|
||||
boolean crossfade = overlayTitleAnimation && !TextUtils.isEmpty(subtitle);
|
||||
if (crossfade) {
|
||||
if (subtitleTextView.getVisibility() != View.VISIBLE) {
|
||||
subtitleTextView.setVisibility(View.VISIBLE);
|
||||
|
@ -1423,4 +1444,68 @@ public class ActionBar extends FrameLayout {
|
|||
public void setOverlayTitleAnimation(boolean ovelayTitleAnimation) {
|
||||
this.overlayTitleAnimation = ovelayTitleAnimation;
|
||||
}
|
||||
|
||||
public void beginDelayedTransition() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
TransitionSet transitionSet = new TransitionSet();
|
||||
transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
|
||||
transitionSet.addTransition(new Fade());
|
||||
transitionSet.addTransition(new ChangeBounds() {
|
||||
|
||||
|
||||
public void captureStartValues(TransitionValues transitionValues) {
|
||||
super.captureStartValues(transitionValues);
|
||||
if (transitionValues.view instanceof SimpleTextView) {
|
||||
float textSize = ((SimpleTextView) transitionValues.view).getTextPaint().getTextSize();
|
||||
transitionValues.values.put("text_size", textSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void captureEndValues(TransitionValues transitionValues) {
|
||||
super.captureEndValues(transitionValues);
|
||||
if (transitionValues.view instanceof SimpleTextView) {
|
||||
float textSize= ((SimpleTextView) transitionValues.view).getTextPaint().getTextSize();
|
||||
transitionValues.values.put("text_size", textSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
|
||||
if (startValues != null && startValues.view instanceof SimpleTextView) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
|
||||
float s = (float) startValues.values.get("text_size") / (float) endValues.values.get("text_size");
|
||||
startValues.view.setScaleX(s);
|
||||
startValues.view.setScaleY(s);
|
||||
if (animator != null) {
|
||||
animatorSet.playTogether(animator);
|
||||
}
|
||||
animatorSet.playTogether(ObjectAnimator.ofFloat(startValues.view, SCALE_X, 1f));
|
||||
animatorSet.playTogether(ObjectAnimator.ofFloat(startValues.view, SCALE_Y, 1f));
|
||||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
super.onAnimationStart(animation);
|
||||
startValues.view.setLayerType(LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
startValues.view.setLayerType(LAYER_TYPE_NONE, null);
|
||||
}
|
||||
});
|
||||
return animatorSet;
|
||||
} else {
|
||||
return super.createAnimator(sceneRoot, startValues, endValues);
|
||||
}
|
||||
}
|
||||
});
|
||||
centerScale = false;
|
||||
transitionSet.setDuration(220);
|
||||
transitionSet.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||
TransitionManager.beginDelayedTransition(this, transitionSet);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -230,7 +230,7 @@ public class ActionBarMenuItem extends FrameLayout {
|
|||
toggleSubMenu();
|
||||
return true;
|
||||
}
|
||||
} else if (popupWindow != null && popupWindow.isShowing()) {
|
||||
} else if (showSubmenuByMove && popupWindow != null && popupWindow.isShowing()) {
|
||||
getLocationOnScreen(location);
|
||||
float x = event.getX() + location[0];
|
||||
float y = event.getY() + location[1];
|
||||
|
@ -246,14 +246,14 @@ public class ActionBarMenuItem extends FrameLayout {
|
|||
if (!rect.contains((int) x, (int) y)) {
|
||||
child.setPressed(false);
|
||||
child.setSelected(false);
|
||||
if (Build.VERSION.SDK_INT == 21) {
|
||||
if (Build.VERSION.SDK_INT == 21 && child.getBackground() != null) {
|
||||
child.getBackground().setVisible(false, false);
|
||||
}
|
||||
} else {
|
||||
child.setPressed(true);
|
||||
child.setSelected(true);
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (Build.VERSION.SDK_INT == 21) {
|
||||
if (Build.VERSION.SDK_INT == 21 && child.getBackground() != null) {
|
||||
child.getBackground().setVisible(true, false);
|
||||
}
|
||||
child.drawableHotspotChanged(x, y - child.getTop());
|
||||
|
@ -272,7 +272,7 @@ public class ActionBarMenuItem extends FrameLayout {
|
|||
delegate.onItemClick((Integer) selectedMenuView.getTag());
|
||||
}
|
||||
popupWindow.dismiss(allowCloseAnimation);
|
||||
} else {
|
||||
} else if (showSubmenuByMove) {
|
||||
popupWindow.dismiss();
|
||||
}
|
||||
} else {
|
||||
|
@ -1553,6 +1553,16 @@ public class ActionBarMenuItem extends FrameLayout {
|
|||
}
|
||||
}
|
||||
|
||||
public void hideAllSubItems() {
|
||||
if (popupLayout == null) {
|
||||
return;
|
||||
}
|
||||
for (int a = 0, N = popupLayout.getItemsCount(); a < N; a++) {
|
||||
popupLayout.getItemAt(a).setVisibility(GONE);
|
||||
}
|
||||
measurePopup = true;
|
||||
}
|
||||
|
||||
public boolean isSubItemVisible(int id) {
|
||||
if (popupLayout == null) {
|
||||
return false;
|
||||
|
|
|
@ -23,6 +23,7 @@ public class ActionBarMenuSubItem extends FrameLayout {
|
|||
private TextView subtextView;
|
||||
private ImageView imageView;
|
||||
private ImageView checkView;
|
||||
private ImageView rightIcon;
|
||||
|
||||
private int textColor = Theme.getColor(Theme.key_actionBarDefaultSubmenuItem);
|
||||
private int iconColor = Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon);
|
||||
|
@ -88,6 +89,20 @@ public class ActionBarMenuSubItem extends FrameLayout {
|
|||
checkView.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
|
||||
public void setRightIcon(int icon) {
|
||||
if (rightIcon == null) {
|
||||
rightIcon = new ImageView(getContext());
|
||||
rightIcon.setScaleType(ImageView.ScaleType.CENTER);
|
||||
rightIcon.setColorFilter(textColor, PorterDuff.Mode.MULTIPLY);
|
||||
if (LocaleController.isRTL) {
|
||||
rightIcon.setScaleX(-1);
|
||||
}
|
||||
addView(rightIcon, LayoutHelper.createFrame(24, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)));
|
||||
}
|
||||
setPadding(AndroidUtilities.dp(LocaleController.isRTL ? 8 : 18), 0, AndroidUtilities.dp(LocaleController.isRTL ? 18 : 8), 0);
|
||||
rightIcon.setImageResource(icon);
|
||||
}
|
||||
|
||||
public void setTextAndIcon(CharSequence text, int icon) {
|
||||
setTextAndIcon(text, icon, null);
|
||||
}
|
||||
|
@ -108,9 +123,10 @@ public class ActionBarMenuSubItem extends FrameLayout {
|
|||
}
|
||||
}
|
||||
|
||||
public void setColors(int textColor, int iconColor) {
|
||||
public ActionBarMenuSubItem setColors(int textColor, int iconColor) {
|
||||
setTextColor(textColor);
|
||||
setIconColor(iconColor);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setTextColor(int textColor) {
|
||||
|
|
|
@ -14,6 +14,8 @@ import android.view.Window;
|
|||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.recyclerview.widget.ChatListItemAnimator;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.NotificationCenter;
|
||||
import org.telegram.messenger.SharedConfig;
|
||||
|
@ -24,7 +26,7 @@ import java.util.ArrayList;
|
|||
|
||||
public class AdjustPanLayoutHelper {
|
||||
|
||||
public final static Interpolator keyboardInterpolator = CubicBezierInterpolator.DEFAULT;
|
||||
public final static Interpolator keyboardInterpolator = ChatListItemAnimator.DEFAULT_INTERPOLATOR;
|
||||
public final static long keyboardDuration = 250;
|
||||
|
||||
private final View parent;
|
||||
|
@ -33,6 +35,15 @@ public class AdjustPanLayoutHelper {
|
|||
private ViewGroup contentView;
|
||||
private View resizableView;
|
||||
private boolean animationInProgress;
|
||||
private boolean needDelay;
|
||||
private Runnable delayedAnimationRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (animator != null && !animator.isRunning()) {
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int previousHeight = -1;
|
||||
int previousContentHeight = -1;
|
||||
|
@ -148,11 +159,16 @@ public class AdjustPanLayoutHelper {
|
|||
onTransitionEnd();
|
||||
}
|
||||
});
|
||||
animator.setDuration(220);
|
||||
animator.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||
animator.setDuration(keyboardDuration);
|
||||
animator.setInterpolator(keyboardInterpolator);
|
||||
|
||||
notificationsIndex = NotificationCenter.getInstance(selectedAccount).setAnimationInProgress(notificationsIndex, null);
|
||||
animator.start();
|
||||
if (needDelay) {
|
||||
needDelay = false;
|
||||
AndroidUtilities.runOnUIThread(delayedAnimationRunnable, 100);
|
||||
} else {
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void setViewHeight(int height) {
|
||||
|
@ -269,4 +285,13 @@ public class AdjustPanLayoutHelper {
|
|||
public void setCheckHierarchyHeight(boolean checkHierarchyHeight) {
|
||||
this.checkHierarchyHeight = checkHierarchyHeight;
|
||||
}
|
||||
|
||||
public void delayAnimation() {
|
||||
needDelay = true;
|
||||
}
|
||||
|
||||
public void runDelayedAnimation() {
|
||||
AndroidUtilities.cancelRunOnUIThread(delayedAnimationRunnable);
|
||||
delayedAnimationRunnable.run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MotionEvent;
|
||||
|
|
|
@ -32,6 +32,7 @@ import android.graphics.PixelFormat;
|
|||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RadialGradient;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
|
@ -105,6 +106,7 @@ import org.telegram.ui.Components.SendingFileDrawable;
|
|||
import org.telegram.ui.Components.StatusDrawable;
|
||||
import org.telegram.ui.Components.ThemeEditorView;
|
||||
import org.telegram.ui.Components.TypingDotsDrawable;
|
||||
import org.telegram.ui.RoundVideoProgressShadow;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -125,6 +127,9 @@ import java.util.concurrent.CountDownLatch;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import tw.nekomimi.nekogram.NekoConfig;
|
||||
|
||||
public class Theme {
|
||||
|
@ -2222,6 +2227,9 @@ public class Theme {
|
|||
public static Paint chat_composeBackgroundPaint;
|
||||
public static Paint chat_radialProgressPaint;
|
||||
public static Paint chat_radialProgress2Paint;
|
||||
public static Paint chat_radialProgressPausedPaint;
|
||||
public static Paint chat_radialProgressPausedSeekbarPaint;
|
||||
|
||||
public static TextPaint chat_msgTextPaint;
|
||||
public static TextPaint chat_actionTextPaint;
|
||||
public static TextPaint chat_msgBotButtonPaint;
|
||||
|
@ -3167,6 +3175,9 @@ public class Theme {
|
|||
private static ThreadLocal<float[]> hsvTemp4Local = new ThreadLocal<>();
|
||||
private static ThreadLocal<float[]> hsvTemp5Local = new ThreadLocal<>();
|
||||
|
||||
private static FragmentContextViewWavesDrawable fragmentContextViewWavesDrawable;
|
||||
private static RoundVideoProgressShadow roundPlayDrawable;
|
||||
|
||||
static {
|
||||
defaultColors.put(key_dialogBackground, 0xffffffff);
|
||||
defaultColors.put(key_dialogBackgroundGray, 0xfff0f0f0);
|
||||
|
@ -7490,10 +7501,6 @@ public class Theme {
|
|||
chat_statusRecordPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
chat_actionTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_actionTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_actionBackgroundPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_actionBackgroundSelectedPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_actionBackgroundGradientDarkenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_actionBackgroundGradientDarkenPaint.setColor(0x2a000000);
|
||||
chat_timeBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
@ -7501,6 +7508,20 @@ public class Theme {
|
|||
chat_contextResult_titleTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
chat_contextResult_descriptionTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_composeBackgroundPaint = new Paint();
|
||||
chat_radialProgressPausedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
chat_radialProgressPausedSeekbarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
if (chat_actionBackgroundPaint == null) {
|
||||
chat_actionBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
if (chat_actionBackgroundSelectedPaint == null) {
|
||||
chat_actionBackgroundSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
if (chat_actionBackgroundPaint2 == null) {
|
||||
chat_actionBackgroundPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
if (chat_actionBackgroundSelectedPaint2 == null) {
|
||||
chat_actionBackgroundSelectedPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8074,6 +8095,8 @@ public class Theme {
|
|||
}
|
||||
if (servicePressedColor == null) {
|
||||
servicePressedColor = serviceSelectedMessageColor;
|
||||
}
|
||||
if (servicePressedColor2 == null) {
|
||||
servicePressedColor2 = serviceSelectedMessage2Color;
|
||||
}
|
||||
|
||||
|
@ -9046,12 +9069,17 @@ public class Theme {
|
|||
return statusDrawable;
|
||||
}
|
||||
|
||||
private static FragmentContextViewWavesDrawable fragmentContextViewWavesDrawable;
|
||||
|
||||
public static FragmentContextViewWavesDrawable getFragmentContextViewWavesDrawable() {
|
||||
if (fragmentContextViewWavesDrawable == null) {
|
||||
fragmentContextViewWavesDrawable = new FragmentContextViewWavesDrawable();
|
||||
}
|
||||
return fragmentContextViewWavesDrawable;
|
||||
}
|
||||
|
||||
public static RoundVideoProgressShadow getRadialSeekbarShadowDrawable() {
|
||||
if (roundPlayDrawable == null) {
|
||||
roundPlayDrawable = new RoundVideoProgressShadow();
|
||||
}
|
||||
return roundPlayDrawable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
|
||||
package org.telegram.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.view.View;
|
||||
|
@ -22,17 +25,23 @@ import org.telegram.messenger.AccountInstance;
|
|||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.ContactsController;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.ImageLoader;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.NotificationCenter;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.SharedConfig;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.messenger.camera.CameraController;
|
||||
import org.telegram.ui.ActionBar.ActionBarLayout;
|
||||
import org.telegram.ui.ActionBar.AlertDialog;
|
||||
import org.telegram.ui.ActionBar.BaseFragment;
|
||||
import org.telegram.ui.ActionBar.DrawerLayoutContainer;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.PasscodeView;
|
||||
import org.telegram.ui.Components.ThemeEditorView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
@ -231,6 +240,106 @@ public class BubbleActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
onFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
ThemeEditorView editorView = ThemeEditorView.getInstance();
|
||||
if (editorView != null) {
|
||||
editorView.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
if (actionBarLayout.fragmentsStack.size() != 0) {
|
||||
BaseFragment fragment = actionBarLayout.fragmentsStack.get(actionBarLayout.fragmentsStack.size() - 1);
|
||||
fragment.onActivityResultFragment(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (grantResults == null) {
|
||||
grantResults = new int[0];
|
||||
}
|
||||
if (permissions == null) {
|
||||
permissions = new String[0];
|
||||
}
|
||||
|
||||
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
if (requestCode == 104) {
|
||||
if (granted) {
|
||||
if (GroupCallActivity.groupCallInstance != null) {
|
||||
GroupCallActivity.groupCallInstance.enableCamera();
|
||||
}
|
||||
} else {
|
||||
showPermissionErrorAlert(LocaleController.getString("VoipNeedCameraPermission", R.string.VoipNeedCameraPermission));
|
||||
}
|
||||
} else if (requestCode == 4) {
|
||||
if (!granted) {
|
||||
showPermissionErrorAlert(LocaleController.getString("PermissionStorage", R.string.PermissionStorage));
|
||||
} else {
|
||||
ImageLoader.getInstance().checkMediaPaths();
|
||||
}
|
||||
} else if (requestCode == 5) {
|
||||
if (!granted) {
|
||||
showPermissionErrorAlert(LocaleController.getString("PermissionContacts", R.string.PermissionContacts));
|
||||
return;
|
||||
} else {
|
||||
ContactsController.getInstance(currentAccount).forceImportContacts();
|
||||
}
|
||||
} else if (requestCode == 3) {
|
||||
boolean audioGranted = true;
|
||||
boolean cameraGranted = true;
|
||||
for (int i = 0, size = Math.min(permissions.length, grantResults.length); i < size; i++) {
|
||||
if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])) {
|
||||
audioGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
|
||||
} else if (Manifest.permission.CAMERA.equals(permissions[i])) {
|
||||
cameraGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
}
|
||||
if (!audioGranted) {
|
||||
showPermissionErrorAlert(LocaleController.getString("PermissionNoAudio", R.string.PermissionNoAudio));
|
||||
} else if (!cameraGranted) {
|
||||
showPermissionErrorAlert(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera));
|
||||
} else {
|
||||
if (SharedConfig.inappCamera) {
|
||||
CameraController.getInstance().initCamera(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (requestCode == 18 || requestCode == 19 || requestCode == 20 || requestCode == 22) {
|
||||
if (!granted) {
|
||||
showPermissionErrorAlert(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera));
|
||||
}
|
||||
} else if (requestCode == 2) {
|
||||
if (granted) {
|
||||
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.locationPermissionGranted);
|
||||
}
|
||||
}
|
||||
if (actionBarLayout.fragmentsStack.size() != 0) {
|
||||
BaseFragment fragment = actionBarLayout.fragmentsStack.get(actionBarLayout.fragmentsStack.size() - 1);
|
||||
fragment.onRequestPermissionsResultFragment(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
VoIPFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
private void showPermissionErrorAlert(String message) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
||||
builder.setMessage(message);
|
||||
builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> {
|
||||
try {
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName()));
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
|
|
@ -97,7 +97,11 @@ public class AboutLinkCell extends FrameLayout {
|
|||
if (TextUtils.isEmpty(text) || TextUtils.equals(text, oldText)) {
|
||||
return;
|
||||
}
|
||||
oldText = text;
|
||||
try {
|
||||
oldText = AndroidUtilities.getSafeString(text);
|
||||
} catch (Throwable e) {
|
||||
oldText = text;
|
||||
}
|
||||
stringBuilder = new SpannableStringBuilder(oldText);
|
||||
MessageObject.addLinks(false, stringBuilder, false, false, !parseLinks);
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
|
|
|
@ -10,7 +10,6 @@ import android.view.ViewGroup;
|
|||
import android.widget.FrameLayout;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.Components.BottomPagesView;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
|
@ -54,12 +53,12 @@ public class ArchiveHintCell extends FrameLayout {
|
|||
|
||||
@Override
|
||||
public void onPageSelected(int i) {
|
||||
FileLog.d("test1");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int i) {
|
||||
FileLog.d("test1");
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -38,10 +38,11 @@ public abstract class BaseCell extends ViewGroup {
|
|||
if (!NekoConfig.disableVibration) {
|
||||
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
}
|
||||
onLongPress();
|
||||
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
onTouchEvent(event);
|
||||
event.recycle();
|
||||
if (onLongPress()) {
|
||||
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
onTouchEvent(event);
|
||||
event.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +104,7 @@ public abstract class BaseCell extends ViewGroup {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected void onLongPress() {
|
||||
|
||||
protected boolean onLongPress() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public class BotHelpCell extends View {
|
|||
if (text != null && text.equals(oldText)) {
|
||||
return;
|
||||
}
|
||||
oldText = text;
|
||||
oldText = AndroidUtilities.getSafeString(text);
|
||||
setVisibility(VISIBLE);
|
||||
int maxWidth;
|
||||
if (AndroidUtilities.isTablet()) {
|
||||
|
|
|
@ -246,10 +246,11 @@ public class ChatActionCell extends BaseCell implements DownloadController.FileD
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onLongPress() {
|
||||
protected boolean onLongPress() {
|
||||
if (delegate != null) {
|
||||
delegate.didLongPress(this, lastTouchX, lastTouchY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -48,7 +48,7 @@ import tw.nekomimi.nekogram.NekoConfig;
|
|||
public class SharedLinkCell extends FrameLayout {
|
||||
|
||||
public interface SharedLinkCellDelegate {
|
||||
void needOpenWebView(TLRPC.WebPage webPage);
|
||||
void needOpenWebView(TLRPC.WebPage webPage, MessageObject messageObject);
|
||||
boolean canPerformActions();
|
||||
void onLinkPress(final String urlFinal, boolean longPress);
|
||||
}
|
||||
|
@ -452,6 +452,10 @@ public class SharedLinkCell extends FrameLayout {
|
|||
requestLayout();
|
||||
}
|
||||
|
||||
public ImageReceiver getLinkImageView() {
|
||||
return linkImageView;
|
||||
}
|
||||
|
||||
public void setDelegate(SharedLinkCellDelegate sharedLinkCellDelegate) {
|
||||
delegate = sharedLinkCellDelegate;
|
||||
}
|
||||
|
@ -508,7 +512,7 @@ public class SharedLinkCell extends FrameLayout {
|
|||
try {
|
||||
TLRPC.WebPage webPage = pressedLink == 0 && message.messageOwner.media != null ? message.messageOwner.media.webpage : null;
|
||||
if (webPage != null && webPage.embed_url != null && webPage.embed_url.length() != 0) {
|
||||
delegate.needOpenWebView(webPage);
|
||||
delegate.needOpenWebView(webPage, message);
|
||||
} else {
|
||||
delegate.onLinkPress(links.get(pressedLink), false);
|
||||
}
|
||||
|
|
|
@ -435,7 +435,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio
|
|||
if (messageObject1.isVoice() || messageObject1.isMusic()) {
|
||||
cell.updateButtonState(false, true, false);
|
||||
} else if (messageObject1.isRoundVideo()) {
|
||||
cell.checkVideoPlayback(false);
|
||||
cell.checkVideoPlayback(false, null);
|
||||
if (!MediaController.getInstance().isPlayingMessage(messageObject1)) {
|
||||
if (messageObject1.audioProgress != 0) {
|
||||
messageObject1.resetPlayingProgress();
|
||||
|
@ -460,7 +460,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio
|
|||
cell.updateButtonState(false, true, false);
|
||||
} else if (messageObject.isRoundVideo()) {
|
||||
if (!MediaController.getInstance().isPlayingMessage(messageObject)) {
|
||||
cell.checkVideoPlayback(true);
|
||||
cell.checkVideoPlayback(true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2227,8 +2227,8 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio
|
|||
}
|
||||
|
||||
@Override
|
||||
public void needOpenWebView(String url, String title, String description, String originalUrl, int w, int h) {
|
||||
EmbedBottomSheet.show(mContext, title, description, originalUrl, url, w, h, false);
|
||||
public void needOpenWebView(MessageObject message, String url, String title, String description, String originalUrl, int w, int h) {
|
||||
EmbedBottomSheet.show(getParentActivity(), message, provider, title, description, originalUrl, url, w, h, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -648,6 +648,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
private boolean scrollToVideo;
|
||||
private Path aspectPath;
|
||||
private Paint aspectPaint;
|
||||
private Runnable destroyTextureViewRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
destroyTextureView();
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean noForwardQuote;
|
||||
private TLRPC.ChatParticipant selectedParticipant;
|
||||
|
@ -1192,6 +1198,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
chatListView.startMultiselect(position, false, new RecyclerListView.onMultiSelectionChanged() {
|
||||
boolean limitReached;
|
||||
|
||||
@Override
|
||||
public void onSelectionChanged(int position, boolean selected, float x, float y) {
|
||||
int i = position - chatAdapter.messagesStartRow;
|
||||
|
@ -2799,7 +2806,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
invalidateChatListViewTopPadding();
|
||||
invalidateMessagesVisiblePart();
|
||||
}
|
||||
chatListView.setItemAnimator(null);
|
||||
chatListView.invalidate();
|
||||
updateBulletinLayout();
|
||||
}
|
||||
|
@ -2939,9 +2945,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (Theme.chat_roundVideoShadow != null && aspectRatioFrameLayout.isDrawingReady()) {
|
||||
int x = (int) child.getX() - AndroidUtilities.dp(3);
|
||||
int y = (int) child.getY() - AndroidUtilities.dp(2);
|
||||
canvas.save();
|
||||
canvas.scale(videoPlayerContainer.getScaleX(), videoPlayerContainer.getScaleY(), child.getX(), child.getY());
|
||||
Theme.chat_roundVideoShadow.setAlpha(255);
|
||||
Theme.chat_roundVideoShadow.setBounds(x, y, x + AndroidUtilities.roundMessageSize + AndroidUtilities.dp(6), y + AndroidUtilities.roundMessageSize + AndroidUtilities.dp(6));
|
||||
Theme.chat_roundVideoShadow.setBounds(x, y, x + AndroidUtilities.roundPlayingMessageSize + AndroidUtilities.dp(6), y + AndroidUtilities.roundPlayingMessageSize + AndroidUtilities.dp(6));
|
||||
Theme.chat_roundVideoShadow.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
result = super.drawChild(canvas, child, drawingTime);
|
||||
} else {
|
||||
|
@ -2963,7 +2972,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
canvas.translate(drawLaterRoundProgressCell.getX(), drawLaterRoundProgressCell.getTop() + chatListView.getY());
|
||||
if (isRoundVideo) {
|
||||
drawLaterRoundProgressCell.drawRoundProgress(canvas);
|
||||
drawLaterRoundProgressCell.drawOverlays(canvas);
|
||||
invalidate();
|
||||
drawLaterRoundProgressCell.invalidate();
|
||||
// drawLaterRoundProgressCell.drawOverlays(canvas);
|
||||
} else {
|
||||
drawLaterRoundProgressCell.drawOverlays(canvas);
|
||||
if (drawLaterRoundProgressCell.needDrawTime()) {
|
||||
|
@ -3012,6 +3023,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
invalidateMessagesVisiblePart = false;
|
||||
updateMessagesVisiblePart(false);
|
||||
}
|
||||
updateTextureViewPosition(false);
|
||||
super.dispatchDraw(canvas);
|
||||
if (fragmentContextView != null && fragmentContextView.isCallStyle()) {
|
||||
canvas.save();
|
||||
|
@ -3109,6 +3121,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
groupedBackgroundWasDraw = true;
|
||||
}
|
||||
|
||||
if (cell != null && cell.getPhotoImage().isAnimationRunning()) {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
float viewClipLeft = Math.max(chatListView.getLeft(), chatListView.getLeft() + child.getX());
|
||||
float viewClipTop = Math.max(listTop, chatListView.getTop() + child.getY());
|
||||
float viewClipRight = Math.min(chatListView.getRight(), chatListView.getLeft() + child.getX() + child.getMeasuredWidth());
|
||||
|
@ -3253,6 +3269,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (actionBar.getVisibility() == VISIBLE) {
|
||||
heightSize -= actionBarHeight;
|
||||
}
|
||||
int keyboardHeightOld = keyboardHeight + chatEmojiViewPadding;
|
||||
boolean keyboardVisibleOld = keyboardHeight + chatEmojiViewPadding >= AndroidUtilities.dp(20);
|
||||
if (lastHeight != allHeight) {
|
||||
measureKeyboardHeight();
|
||||
}
|
||||
|
@ -3266,9 +3284,34 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
chatEmojiViewPadding = 0;
|
||||
}
|
||||
}
|
||||
|
||||
setEmojiKeyboardHeight(chatEmojiViewPadding);
|
||||
|
||||
boolean keyboardVisible = keyboardHeight + chatEmojiViewPadding >= AndroidUtilities.dp(20);
|
||||
boolean waitingChatListItemAnimator = false;
|
||||
if (MediaController.getInstance().getPlayingMessageObject() != null && MediaController.getInstance().getPlayingMessageObject().isRoundVideo() && keyboardVisibleOld != keyboardVisible) {
|
||||
for (int i = 0; i < chatListView.getChildCount(); i++) {
|
||||
View child = chatListView.getChildAt(i);
|
||||
if (child instanceof ChatMessageCell) {
|
||||
MessageObject messageObject = ((ChatMessageCell) child).getMessageObject();
|
||||
if (messageObject.isRoundVideo() && MediaController.getInstance().isPlayingMessage(messageObject)) {
|
||||
int p = chatListView.getChildAdapterPosition(child);
|
||||
if (p >= 0) {
|
||||
chatLayoutManager.scrollToPositionWithOffset(p, (int) ((chatListView.getMeasuredHeight() - chatListViewPaddingTop + (keyboardHeight + chatEmojiViewPadding - keyboardHeightOld) - (keyboardVisible ? AndroidUtilities.roundMessageSize : AndroidUtilities.roundPlayingMessageSize)) / 2), false);
|
||||
chatAdapter.notifyItemChanged(p);
|
||||
adjustPanLayoutHelper.delayAnimation();
|
||||
waitingChatListItemAnimator = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!waitingChatListItemAnimator) {
|
||||
chatActivityEnterView.runEmojiPanelAnimation();
|
||||
}
|
||||
|
||||
|
||||
int childCount = getChildCount();
|
||||
measureChildWithMargins(chatActivityEnterView, widthMeasureSpec, 0, heightMeasureSpec, 0);
|
||||
|
||||
|
@ -3422,7 +3465,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
final int count = getChildCount();
|
||||
int keyboardSize = getKeyboardHeight();
|
||||
int paddingBottom;
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
if (fixedKeyboardHeight > 0 && keyboardSize <= AndroidUtilities.dp(20)) {
|
||||
paddingBottom = fixedKeyboardHeight;
|
||||
} else {
|
||||
|
@ -3430,10 +3473,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
if (!SharedConfig.smoothKeyboard) {
|
||||
setBottomClip(paddingBottom);
|
||||
} else if (!inPreviewMode && chatActivityEnterView.getEmojiPadding() == 0) {
|
||||
setBottomClip(AndroidUtilities.dp(48));
|
||||
} else {
|
||||
setBottomClip(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
@ -3793,6 +3832,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
|
||||
private RectF rect = new RectF();
|
||||
|
||||
private void drawReplyButton(Canvas canvas) {
|
||||
if (slidingView == null) {
|
||||
return;
|
||||
|
@ -4023,10 +4063,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
drawReplyButton(c);
|
||||
}
|
||||
|
||||
if (chatListView.isFastScrollAnimationRunning()) {
|
||||
updateTextureViewPosition(false);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<MessageObject.GroupedMessages> drawingGroups = new ArrayList<>(10);
|
||||
|
@ -4562,11 +4598,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
float tx = chatMessageCell.getSlidingOffsetX() + chatMessageCell.getCheckBoxTranslation();
|
||||
|
||||
|
||||
int y = (int) ((replaceAnimation ? child.getTop() : child.getY()) + chatMessageCell.getLayoutHeight());
|
||||
int y = (int) ((replaceAnimation ? child.getTop() : child.getY()) + chatMessageCell.getLayoutHeight() + chatMessageCell.getTransitionParams().deltaBottom);
|
||||
int maxY = chatListView.getMeasuredHeight() - chatListView.getPaddingBottom();
|
||||
if (y > maxY) {
|
||||
y = maxY;
|
||||
if (chatMessageCell.isPlayingRound() || chatMessageCell.getTransitionParams().animatePlayingRound) {
|
||||
if (chatMessageCell.getTransitionParams().animatePlayingRound) {
|
||||
float progressLocal = chatMessageCell.getTransitionParams().animateChangeProgress;
|
||||
if (!chatMessageCell.isPlayingRound()) {
|
||||
progressLocal = 1f - progressLocal;
|
||||
}
|
||||
int fromY = y;
|
||||
int toY = y > maxY ? maxY : y;
|
||||
y = (int) (fromY * progressLocal + toY * (1f - progressLocal));
|
||||
}
|
||||
} else {
|
||||
if (y > maxY) {
|
||||
y = maxY;
|
||||
}
|
||||
}
|
||||
|
||||
if (!replaceAnimation && child.getTranslationY() != 0) {
|
||||
|
@ -4655,7 +4702,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
y = top + AndroidUtilities.dp(48);
|
||||
}
|
||||
if (!chatMessageCell.drawPinnedBottom()) {
|
||||
int cellBottom = replaceAnimation ? chatMessageCell.getBottom() : (int) (chatMessageCell.getY() + chatMessageCell.getMeasuredHeight());
|
||||
int cellBottom = replaceAnimation ? chatMessageCell.getBottom() : (int) (chatMessageCell.getY() + chatMessageCell.getMeasuredHeight() + chatMessageCell.getTransitionParams().deltaBottom);
|
||||
if (y > cellBottom) {
|
||||
y = cellBottom;
|
||||
}
|
||||
|
@ -4748,6 +4795,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("chatItemAnimator disable notifications");
|
||||
}
|
||||
chatActivityEnterView.getAdjustPanLayoutHelper().runDelayedAnimation();
|
||||
chatActivityEnterView.runEmojiPanelAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6153,7 +6202,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
if (result.type.equals("video") || result.type.equals("web_player_video")) {
|
||||
int[] size = MessageObject.getInlineResultWidthAndHeight(result);
|
||||
EmbedBottomSheet.show(getParentActivity(), result.title != null ? result.title : "", result.description, result.content.url, result.content.url, size[0], size[1], isKeyboardVisible());
|
||||
EmbedBottomSheet.show(getParentActivity(), null, botContextProvider, result.title != null ? result.title : "", result.description, result.content.url, result.content.url, size[0], size[1], isKeyboardVisible());
|
||||
} else {
|
||||
processExternalUrl(0, result.content.url, false);
|
||||
}
|
||||
|
@ -6394,8 +6443,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
contentView.addView(fragmentLocationContextView = new FragmentContextView(context, this, true), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0));
|
||||
contentView.addView(fragmentContextView = new FragmentContextView(context, this, false) {
|
||||
@Override
|
||||
protected void playbackSpeedChanged(boolean enabled) {
|
||||
undoView.showWithAction(0, enabled ? UndoView.ACTION_PLAYBACK_SPEED_ENABLED : UndoView.ACTION_PLAYBACK_SPEED_DISABLED, null);
|
||||
protected void playbackSpeedChanged(float value) {
|
||||
if (Math.abs(value - 1.0f) < 0.001f || Math.abs(value - 1.8f) < 0.001f) {
|
||||
undoView.showWithAction(0, Math.abs(value - 1.0f) > 0.001f ? UndoView.ACTION_PLAYBACK_SPEED_ENABLED : UndoView.ACTION_PLAYBACK_SPEED_DISABLED, value, null, null);
|
||||
}
|
||||
}
|
||||
}, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0));
|
||||
fragmentContextView.setAdditionalContextView(fragmentLocationContextView);
|
||||
|
@ -6607,7 +6658,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
messageEditTextAnimator = a;
|
||||
a.setDuration(ChatListItemAnimator.DEFAULT_DURATION);
|
||||
// a.setStartDelay(chatActivityEnterViewAnimateBeforeSending ? 20 : 0);
|
||||
// a.setStartDelay(chatActivityEnterViewAnimateBeforeSending ? 20 : 0);
|
||||
a.setInterpolator(ChatListItemAnimator.DEFAULT_INTERPOLATOR);
|
||||
a.start();
|
||||
shouldAnimateEditTextWithBounds = false;
|
||||
|
@ -8335,6 +8386,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (parentLayout == null) {
|
||||
return null;
|
||||
}
|
||||
AndroidUtilities.cancelRunOnUIThread(destroyTextureViewRunnable);
|
||||
if (videoPlayerContainer == null) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
videoPlayerContainer = new FrameLayout(getParentActivity()) {
|
||||
|
@ -8358,7 +8410,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), maxRad);
|
||||
} else {
|
||||
outline.setOval(0, 0, AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize);
|
||||
outline.setOval(0, 0, AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -8432,7 +8484,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
parent = null;
|
||||
}
|
||||
if (parent == null) {
|
||||
contentView.addView(videoPlayerContainer, 1, new FrameLayout.LayoutParams(AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize));
|
||||
contentView.addView(videoPlayerContainer, 1, new FrameLayout.LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize));
|
||||
}
|
||||
videoPlayerContainer.setTag(null);
|
||||
aspectRatioFrameLayout.setDrawingReady(false);
|
||||
|
@ -8443,12 +8495,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (videoPlayerContainer == null || videoPlayerContainer.getParent() == null) {
|
||||
return;
|
||||
}
|
||||
contentView.removeView(videoPlayerContainer);
|
||||
chatListView.invalidateViews();
|
||||
aspectRatioFrameLayout.setDrawingReady(false);
|
||||
videoPlayerContainer.setTag(null);
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
videoPlayerContainer.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
contentView.removeView(videoPlayerContainer);
|
||||
}
|
||||
|
||||
private void openForward() {
|
||||
|
@ -9171,7 +9224,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
String str = StrUtil.utf8Str(os.toByteArray());
|
||||
if (StrUtil.isBlank(str)) return;
|
||||
getSendMessagesHelper().sendMessage(str, dialog_id, null, null, null,
|
||||
false, null, null, null, true, 0,null);
|
||||
false, null, null, null, true, 0, null);
|
||||
afterMessageSend();
|
||||
hideFieldPanel(false);
|
||||
break;
|
||||
|
@ -10870,12 +10923,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) videoPlayerContainer.getLayoutParams();
|
||||
if (messageObject.isRoundVideo()) {
|
||||
videoPlayerContainer.setTag(R.id.parent_tag, null);
|
||||
if (layoutParams.width != AndroidUtilities.roundMessageSize || layoutParams.height != AndroidUtilities.roundMessageSize) {
|
||||
layoutParams.width = layoutParams.height = AndroidUtilities.roundMessageSize;
|
||||
if (layoutParams.width != AndroidUtilities.roundPlayingMessageSize || layoutParams.height != AndroidUtilities.roundPlayingMessageSize) {
|
||||
layoutParams.width = layoutParams.height = AndroidUtilities.roundPlayingMessageSize;
|
||||
aspectRatioFrameLayout.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
|
||||
videoPlayerContainer.setLayoutParams(layoutParams);
|
||||
}
|
||||
float scale = (AndroidUtilities.roundMessageSize + AndroidUtilities.roundMessageInset * 2) / (float) AndroidUtilities.roundMessageSize;
|
||||
float scale = (AndroidUtilities.roundPlayingMessageSize + AndroidUtilities.roundMessageInset * 2) / (float) AndroidUtilities.roundPlayingMessageSize;
|
||||
float transitionScale = messageCell.getPhotoImage().getImageWidth() / AndroidUtilities.roundPlayingMessageSize;
|
||||
if (videoPlayerContainer.getScaleX() != transitionScale) {
|
||||
videoPlayerContainer.invalidate();
|
||||
fragmentView.invalidate();
|
||||
}
|
||||
videoPlayerContainer.setPivotX(0);
|
||||
videoPlayerContainer.setPivotY(0);
|
||||
videoPlayerContainer.setScaleX(transitionScale);
|
||||
videoPlayerContainer.setScaleY(transitionScale);
|
||||
videoTextureView.setScaleX(scale);
|
||||
videoTextureView.setScaleY(scale);
|
||||
} else {
|
||||
|
@ -10903,9 +10965,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (checkTextureViewPosition && messageObject.isVideo()) {
|
||||
MediaController.getInstance().cleanupPlayer(true, true);
|
||||
} else {
|
||||
videoPlayerContainer.setTranslationY(-AndroidUtilities.roundMessageSize - 100);
|
||||
videoPlayerContainer.setTranslationY(-AndroidUtilities.roundPlayingMessageSize - 100);
|
||||
fragmentView.invalidate();
|
||||
if (messageObject != null && (messageObject.isRoundVideo() || messageObject.isVideo())) {
|
||||
if (messageObject.isRoundVideo() || messageObject.isVideo()) {
|
||||
if (checkTextureViewPosition || PipRoundVideoView.getInstance() != null) {
|
||||
MediaController.getInstance().setCurrentVideoVisible(false);
|
||||
} else {
|
||||
|
@ -10916,7 +10978,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
} else {
|
||||
MediaController.getInstance().setCurrentVideoVisible(true);
|
||||
if (messageObject.isRoundVideo() || scrollToVideo) {
|
||||
scrollToMessageId(messageObject.getId(), 0, false, 0, true, 0);
|
||||
// scrollToMessageId(messageObject.getId(), 0, false, 0, true, 0);
|
||||
} else {
|
||||
chatListView.invalidate();
|
||||
}
|
||||
|
@ -11062,9 +11124,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
foundTextureViewMessage = true;
|
||||
}
|
||||
}
|
||||
if (startFromVideoTimestamp >= 0 && fragmentOpened && !chatListView.isFastScrollAnimationRunning() && startFromVideoMessageId == messageObject.getId()) {
|
||||
if (startFromVideoTimestamp >= 0 && fragmentOpened && !chatListView.isFastScrollAnimationRunning() && startFromVideoMessageId == messageObject.getId() && (messageObject.isVideo() || messageObject.isRoundVideo() || messageObject.isVoice() || messageObject.isMusic())) {
|
||||
messageObject.forceSeekTo = startFromVideoTimestamp / (float) messageObject.getDuration();
|
||||
openPhotoViewerForMessage(messageCell, messageObject);
|
||||
MessageObject finalMessage = messageObject;
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
if (finalMessage.isVideo()) {
|
||||
openPhotoViewerForMessage(null, finalMessage);
|
||||
} else {
|
||||
MediaController.getInstance().playMessage(finalMessage);
|
||||
}
|
||||
}, 40);
|
||||
startFromVideoTimestamp = -1;
|
||||
}
|
||||
} else if (view instanceof ChatActionCell) {
|
||||
|
@ -11161,7 +11230,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (checkTextureViewPosition && messageObject.isVideo()) {
|
||||
MediaController.getInstance().cleanupPlayer(true, true);
|
||||
} else {
|
||||
videoPlayerContainer.setTranslationY(-AndroidUtilities.roundMessageSize - 100);
|
||||
videoPlayerContainer.setTranslationY(-AndroidUtilities.roundPlayingMessageSize - 100);
|
||||
fragmentView.invalidate();
|
||||
if ((messageObject.isRoundVideo() || messageObject.isVideo()) && messageObject.eventId == 0 && checkTextureViewPosition && !chatListView.isFastScrollAnimationRunning()) {
|
||||
MediaController.getInstance().setCurrentVideoVisible(false);
|
||||
|
@ -12927,30 +12996,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
postponedScrollToLastMessageQueryIndex = 0;
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
if (chatMode == MODE_SCHEDULED && mode == MODE_SCHEDULED && !isCache) {
|
||||
waitingForReplyMessageLoad = true;
|
||||
waitingForLoad.add(lastLoadIndex);
|
||||
getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++);
|
||||
}
|
||||
return;
|
||||
} else if (!doNotRemoveLoadIndex) {
|
||||
waitingForLoad.remove(index);
|
||||
if (index == -1) {
|
||||
if (chatMode == MODE_SCHEDULED && mode == MODE_SCHEDULED && !isCache) {
|
||||
waitingForReplyMessageLoad = true;
|
||||
waitingForLoad.add(lastLoadIndex);
|
||||
getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++);
|
||||
}
|
||||
return;
|
||||
} else if (!doNotRemoveLoadIndex) {
|
||||
waitingForLoad.remove(index);
|
||||
}
|
||||
ArrayList<MessageObject> messArr = (ArrayList<MessageObject>) args[2];
|
||||
if (messages.isEmpty() && messArr.size() == 1 && MessageObject.isSystemSignUp(messArr.get(0))) {
|
||||
forceHistoryEmpty = true;
|
||||
endReached[0] = endReached[1] = true;
|
||||
forwardEndReached[0] = forwardEndReached[1] = true;
|
||||
firstLoading = false;
|
||||
showProgressView(false);
|
||||
if (!fragmentOpened) {
|
||||
chatListView.setAnimateEmptyView(false, 1);
|
||||
chatListView.setEmptyView(emptyViewContainer);
|
||||
chatListView.setAnimateEmptyView(true, 1);
|
||||
} else {
|
||||
chatListView.setEmptyView(emptyViewContainer);
|
||||
}
|
||||
ArrayList<MessageObject> messArr = (ArrayList<MessageObject>) args[2];
|
||||
if (messages.isEmpty() && messArr.size() == 1 && MessageObject.isSystemSignUp(messArr.get(0))) {
|
||||
forceHistoryEmpty = true;
|
||||
endReached[0] = endReached[1] = true;
|
||||
forwardEndReached[0] = forwardEndReached[1] = true;
|
||||
firstLoading = false;
|
||||
showProgressView(false);
|
||||
if (!fragmentOpened) {
|
||||
chatListView.setAnimateEmptyView(false, 1);
|
||||
chatListView.setEmptyView(emptyViewContainer);
|
||||
chatListView.setAnimateEmptyView(true, 1);
|
||||
} else {
|
||||
chatListView.setEmptyView(emptyViewContainer);
|
||||
}
|
||||
|
||||
chatAdapter.notifyDataSetChanged();
|
||||
resumeDelayedFragmentAnimation();
|
||||
|
@ -13366,19 +13435,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
|
||||
|
||||
if (messArr.size() <= 3 &&
|
||||
obj.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser &&
|
||||
obj.messageOwner.from_id instanceof TLRPC.TL_peerUser &&
|
||||
obj.messageOwner.from_id.user_id == getUserConfig().getClientUserId()) {
|
||||
TLObject nekoxBot = getMessagesController().getUserOrChat("NekoXBot");
|
||||
if (nekoxBot instanceof TLRPC.User &&
|
||||
action.user_id == ((TLRPC.User) nekoxBot).id) {
|
||||
ArrayList<Integer> mids = new ArrayList<>();
|
||||
mids.add(obj.messageOwner.id);
|
||||
getMessagesController().deleteMessages(mids, null, null, dialog_id, 0, true, false);
|
||||
continue;
|
||||
}
|
||||
if (messArr.size() <= 3 &&
|
||||
obj.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser &&
|
||||
obj.messageOwner.from_id instanceof TLRPC.TL_peerUser &&
|
||||
obj.messageOwner.from_id.user_id == getUserConfig().getClientUserId()) {
|
||||
TLObject nekoxBot = getMessagesController().getUserOrChat("NekoXBot");
|
||||
if (nekoxBot instanceof TLRPC.User &&
|
||||
action.user_id == ((TLRPC.User) nekoxBot).id) {
|
||||
ArrayList<Integer> mids = new ArrayList<>();
|
||||
mids.add(obj.messageOwner.id);
|
||||
getMessagesController().deleteMessages(mids, null, null, dialog_id, 0, true, false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (needAnimateToMessage != null && needAnimateToMessage.getId() == messageId && messageId < 0 && chatMode != MODE_SCHEDULED) {
|
||||
obj = needAnimateToMessage;
|
||||
|
@ -14672,7 +14741,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
if (messageObject1 != null) {
|
||||
boolean isVideo = messageObject1.isVideo();
|
||||
if (messageObject1.isRoundVideo() || isVideo) {
|
||||
cell.checkVideoPlayback(!messageObject.equals(messageObject1));
|
||||
cell.checkVideoPlayback(!messageObject.equals(messageObject1), null);
|
||||
if (!MediaController.getInstance().isPlayingMessage(messageObject1)) {
|
||||
if (isVideo && !MediaController.getInstance().isGoingToShowMessageObject(messageObject1)) {
|
||||
AnimatedFileDrawable animation = cell.getPhotoImage().getAnimation();
|
||||
|
@ -14687,6 +14756,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
} else if (isVideo) {
|
||||
cell.updateButtonState(false, true, false);
|
||||
}
|
||||
if (messageObject1.isRoundVideo()) {
|
||||
int position = chatListView.getChildAdapterPosition(cell);
|
||||
if (position >= 0) {
|
||||
if (MediaController.getInstance().isPlayingMessage(messageObject1)) {
|
||||
boolean keyboardIsVisible = contentView.getKeyboardHeight() >= AndroidUtilities.dp(20);
|
||||
chatLayoutManager.scrollToPositionWithOffset(position, (int) ((chatListView.getMeasuredHeight() - chatListViewPaddingTop - (keyboardIsVisible ? AndroidUtilities.roundMessageSize : AndroidUtilities.roundPlayingMessageSize)) / 2), false);
|
||||
}
|
||||
chatAdapter.notifyItemChanged(position);
|
||||
}
|
||||
}
|
||||
} else if (messageObject1.isVoice() || messageObject1.isMusic()) {
|
||||
cell.updateButtonState(false, true, false);
|
||||
}
|
||||
|
@ -14745,8 +14824,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
} else if (id == NotificationCenter.messagePlayingDidReset || id == NotificationCenter.messagePlayingPlayStateChanged) {
|
||||
if (id == NotificationCenter.messagePlayingDidReset) {
|
||||
destroyTextureView();
|
||||
AndroidUtilities.runOnUIThread(destroyTextureViewRunnable);
|
||||
}
|
||||
int messageId = (int) args[0];
|
||||
if (chatListView != null) {
|
||||
int count = chatListView.getChildCount();
|
||||
for (int a = 0; a < count; a++) {
|
||||
|
@ -14767,7 +14847,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
} else if (messageObject.isRoundVideo()) {
|
||||
if (!MediaController.getInstance().isPlayingMessage(messageObject)) {
|
||||
cell.checkVideoPlayback(true);
|
||||
Bitmap bitmap = null;
|
||||
if (id == NotificationCenter.messagePlayingDidReset && cell.getMessageObject().getId() == messageId && videoTextureView != null) {
|
||||
bitmap = videoTextureView.getBitmap();
|
||||
if (bitmap != null && bitmap.getPixel(0, 0) == Color.TRANSPARENT) {
|
||||
bitmap = null;
|
||||
}
|
||||
}
|
||||
cell.checkVideoPlayback(true, bitmap);
|
||||
}
|
||||
int position = chatListView.getChildAdapterPosition(cell);
|
||||
messageObject.forceUpdate = true;
|
||||
if (position >= 0) {
|
||||
chatAdapter.notifyItemChanged(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21366,7 +21458,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
}
|
||||
SendMessagesHelper.getInstance(currentAccount).sendMessage(toSend.toString(), dialog_id, selectedObject, null, null,
|
||||
false, null, null, null, true, 0,null);
|
||||
false, null, null, null, true, 0, null);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
@ -22356,18 +22448,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
hideFieldPanel(false);
|
||||
}
|
||||
}
|
||||
} else if (messageObject != null && str.startsWith("video")) {
|
||||
} else if (messageObject != null && str.startsWith("video") && !longPress) {
|
||||
int seekTime = Utilities.parseInt(str);
|
||||
TLRPC.WebPage webPage;
|
||||
if (messageObject.isYouTubeVideo()) {
|
||||
webPage = messageObject.messageOwner.media.webpage;
|
||||
} else if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.isYouTubeVideo()) {
|
||||
webPage = messageObject.replyMessageObject.messageOwner.media.webpage;
|
||||
messageObject = messageObject.replyMessageObject;
|
||||
} else {
|
||||
webPage = null;
|
||||
}
|
||||
if (webPage != null) {
|
||||
EmbedBottomSheet.show(getParentActivity(), webPage.site_name, webPage.title, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, seekTime, isKeyboardVisible());
|
||||
EmbedBottomSheet.show(getParentActivity(), messageObject, photoViewerProvider, webPage.site_name, webPage.title, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, seekTime, isKeyboardVisible());
|
||||
} else {
|
||||
if (!messageObject.isVideo() && messageObject.replyMessageObject != null) {
|
||||
MessageObject obj = messagesDict[messageObject.replyMessageObject.getDialogId() == dialog_id ? 0 : 1].get(messageObject.replyMessageObject.getId());
|
||||
|
@ -22443,15 +22536,61 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
} else {
|
||||
if (longPress) {
|
||||
BottomBuilder builder = new BottomBuilder(getParentActivity());
|
||||
builder.addTitle(str);
|
||||
int timestamp = -1;
|
||||
if (str.startsWith("video?")) {
|
||||
timestamp = Utilities.parseInt(str);
|
||||
}
|
||||
if (timestamp >= 0) {
|
||||
builder.addTitle(AndroidUtilities.formatDuration(timestamp, false));
|
||||
} else {
|
||||
builder.addTitle(str);
|
||||
}
|
||||
final int finalTimestamp = timestamp;
|
||||
ChatMessageCell finalCell = cell;
|
||||
MessageObject finalMessageObject = messageObject;
|
||||
builder.addItems(
|
||||
new String[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy), str.startsWith("#") || str.startsWith("$") ? null : LocaleController.getString("ShareQRCode", R.string.ShareQRCode)},
|
||||
new String[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("ShareQRCode", R.string.ShareQRCode)},
|
||||
new int[]{R.drawable.baseline_open_in_browser_24, R.drawable.baseline_content_copy_24, R.drawable.wallet_qr}, (which, text, __) -> {
|
||||
if (which == 0 || which == 2) {
|
||||
openClickableLink(str, which == 2);
|
||||
|
||||
if (which == 0) {
|
||||
if (str.startsWith("video?")) {
|
||||
didPressMessageUrl(url, false, finalMessageObject, finalCell);
|
||||
} else {
|
||||
openClickableLink(str, which == 2);
|
||||
}
|
||||
} else if (which == 1) {
|
||||
AndroidUtilities.addToClipboard(str);
|
||||
if (str.startsWith("video?") && finalMessageObject != null && !finalMessageObject.scheduled) {
|
||||
MessageObject messageObject1 = finalMessageObject;
|
||||
boolean isMedia = finalMessageObject.isVideo() || finalMessageObject.isRoundVideo() || finalMessageObject.isVoice() || finalMessageObject.isMusic();
|
||||
if (!isMedia && finalMessageObject.replyMessageObject != null) {
|
||||
messageObject1 = finalMessageObject.replyMessageObject;
|
||||
}
|
||||
int lower_id = (int) messageObject1.getDialogId();
|
||||
int messageId = messageObject1.getId();
|
||||
String link = null;
|
||||
|
||||
if (messageObject1.messageOwner.fwd_from != null) {
|
||||
lower_id = MessageObject.getPeerId(messageObject1.messageOwner.fwd_from.saved_from_peer);
|
||||
messageId = messageObject1.messageOwner.fwd_from.saved_from_msg_id;
|
||||
}
|
||||
|
||||
if (lower_id < 0) {
|
||||
TLRPC.Chat currentChat = MessagesController.getInstance(currentAccount).getChat(-lower_id);
|
||||
if (currentChat != null && currentChat.username != null) {
|
||||
link = "https://t.me/" + currentChat.username + "/" + messageId + "?t=" + finalTimestamp;
|
||||
}
|
||||
} else {
|
||||
TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id);
|
||||
if (user != null && user.username != null) {
|
||||
link = "https://t.me/" + user.username + "/" + messageId + "?t=" + finalTimestamp;
|
||||
}
|
||||
}
|
||||
if (link == null) {
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
AndroidUtilities.addToClipboard(link);
|
||||
} else {
|
||||
AndroidUtilities.addToClipboard(str);
|
||||
}
|
||||
if (str.startsWith("@")) {
|
||||
undoView.showWithAction(0, UndoView.ACTION_USERNAME_COPIED, null);
|
||||
} else if (str.startsWith("#") || str.startsWith("$")) {
|
||||
|
@ -22459,7 +22598,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
} else {
|
||||
undoView.showWithAction(0, UndoView.ACTION_LINK_COPIED, null);
|
||||
}
|
||||
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
@ -22481,14 +22619,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
} else if (which == 1) {
|
||||
String url1 = urlFinal;
|
||||
boolean tel = false;
|
||||
boolean mail = false;
|
||||
if (url1.startsWith("mailto:")) {
|
||||
url1 = url1.substring(7);
|
||||
mail = true;
|
||||
} else if (url1.startsWith("tel:")) {
|
||||
url1 = url1.substring(4);
|
||||
tel = true;
|
||||
}
|
||||
AndroidUtilities.addToClipboard(url1);
|
||||
if (tel) {
|
||||
if (mail) {
|
||||
undoView.showWithAction(0, UndoView.ACTION_EMAIL_COPIED, null);
|
||||
} else if (tel) {
|
||||
undoView.showWithAction(0, UndoView.ACTION_PHONE_COPIED, null);
|
||||
} else {
|
||||
undoView.showWithAction(0, UndoView.ACTION_LINK_COPIED, null);
|
||||
|
@ -23118,9 +23260,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
|
||||
@Override
|
||||
public void needOpenWebView(String url, String title, String description, String originalUrl, int w, int h) {
|
||||
public void needOpenWebView(MessageObject message, String url, String title, String description, String originalUrl, int w, int h) {
|
||||
try {
|
||||
EmbedBottomSheet.show(mContext, title, description, originalUrl, url, w, h, isKeyboardVisible());
|
||||
EmbedBottomSheet.show(getParentActivity(), message, photoViewerProvider, title, description, originalUrl, url, w, h, isKeyboardVisible());
|
||||
} catch (Throwable e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
|
@ -23419,6 +23561,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
public PinchToZoomHelper getPinchToZoomHelper() {
|
||||
return pinchToZoomHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyboardIsOpened() {
|
||||
return contentView.getKeyboardHeight() + chatEmojiViewPadding >= AndroidUtilities.dp(20);
|
||||
}
|
||||
|
||||
public boolean isLandscape() {
|
||||
return contentView.getMeasuredWidth() > contentView.getMeasuredHeight();
|
||||
}
|
||||
});
|
||||
if (currentEncryptedChat == null) {
|
||||
chatMessageCell.setAllowAssistant(true);
|
||||
|
@ -23721,6 +23872,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
allAnimators.setStartDelay(120);
|
||||
allAnimators.setDuration(180);
|
||||
|
||||
instantCameraView.setIsMessageTransition(true);
|
||||
allAnimators.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
|
@ -23748,6 +23900,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
instantCameraView.setIsMessageTransition(false);
|
||||
instantCameraView.hideCamera(true);
|
||||
instantCameraView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
@ -24311,6 +24464,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
chatActivityDelegate.openReplyMessage(messageId);
|
||||
finishFragment();
|
||||
} else {
|
||||
startFromVideoTimestamp = LaunchActivity.getTimestampFromLink(data);
|
||||
if (startFromVideoTimestamp >= 0) {
|
||||
startFromVideoMessageId = messageId;
|
||||
}
|
||||
scrollToMessageId(messageId, fromMessageId, true, 0, false, 0);
|
||||
}
|
||||
}
|
||||
|
@ -24433,7 +24590,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
|
||||
public static boolean isClickableLink(String str) {
|
||||
return str.startsWith("https://") || str.startsWith("vmess://") || str.startsWith("vmess1://") || str.startsWith("ss://") || str.startsWith("ssr://") || str.startsWith("ws://") || str.startsWith("wss://") || str.startsWith("@") || str.startsWith("#") || str.startsWith("$");
|
||||
return str.startsWith("https://")
|
||||
|| str.startsWith("vmess://")
|
||||
|| str.startsWith("vmess1://")
|
||||
|| str.startsWith("ss://")
|
||||
|| str.startsWith("ssr://")
|
||||
|| str.startsWith("ws://")
|
||||
|| str.startsWith("wss://")
|
||||
|| str.startsWith("@")
|
||||
|| str.startsWith("#")
|
||||
|| str.startsWith("$")
|
||||
|| str.startsWith("video?");
|
||||
}
|
||||
|
||||
public SimpleTextView getReplyNameTextView() {
|
||||
|
|
|
@ -122,7 +122,8 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.
|
|||
private LineProgressView progressView;
|
||||
private SeekBarView seekBarView;
|
||||
private SimpleTextView timeTextView;
|
||||
private ImageView playbackSpeedButton;
|
||||
private ActionBarMenuItem playbackSpeedButton;
|
||||
private ActionBarMenuSubItem[] speedItems = new ActionBarMenuSubItem[4];
|
||||
private TextView durationTextView;
|
||||
private ActionBarMenuItem repeatButton;
|
||||
private ActionBarMenuSubItem repeatSongItem;
|
||||
|
@ -172,6 +173,11 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.
|
|||
long lastRewindingTime;
|
||||
long lastUpdateRewindingPlayerTime;
|
||||
|
||||
private final static int menu_speed_slow = 1;
|
||||
private final static int menu_speed_normal = 2;
|
||||
private final static int menu_speed_fast = 3;
|
||||
private final static int menu_speed_veryfast = 4;
|
||||
|
||||
private final Runnable forwardSeek = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -663,23 +669,47 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.
|
|||
durationTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
playerLayout.addView(durationTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.RIGHT, 0, 96, 20, 0));
|
||||
|
||||
playbackSpeedButton = new ImageView(context);
|
||||
playbackSpeedButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||
playbackSpeedButton.setImageResource(R.drawable.voice2x);
|
||||
playbackSpeedButton = new ActionBarMenuItem(context, null, 0, Theme.getColor(Theme.key_dialogTextBlack));
|
||||
playbackSpeedButton.setLongClickEnabled(false);
|
||||
playbackSpeedButton.setShowSubmenuByMove(false);
|
||||
playbackSpeedButton.setAdditionalYOffset(-AndroidUtilities.dp(224));
|
||||
playbackSpeedButton.setContentDescription(LocaleController.getString("AccDescrPlayerSpeed", R.string.AccDescrPlayerSpeed));
|
||||
if (AndroidUtilities.density >= 3.0f) {
|
||||
playbackSpeedButton.setPadding(0, 1, 0, 0);
|
||||
}
|
||||
playerLayout.addView(playbackSpeedButton, LayoutHelper.createFrame(36, 36, Gravity.TOP | Gravity.RIGHT, 0, 86, 20, 0));
|
||||
playbackSpeedButton.setOnClickListener(v -> {
|
||||
float currentPlaybackSpeed = MediaController.getInstance().getPlaybackSpeed(true);
|
||||
if (currentPlaybackSpeed > 1) {
|
||||
playbackSpeedButton.setDelegate(id -> {
|
||||
float oldSpeed = MediaController.getInstance().getPlaybackSpeed(true);
|
||||
if (id == menu_speed_slow) {
|
||||
MediaController.getInstance().setPlaybackSpeed(true, 0.5f);
|
||||
} else if (id == menu_speed_normal) {
|
||||
MediaController.getInstance().setPlaybackSpeed(true, 1.0f);
|
||||
} else if (id == menu_speed_fast) {
|
||||
MediaController.getInstance().setPlaybackSpeed(true, 1.5f);
|
||||
} else {
|
||||
MediaController.getInstance().setPlaybackSpeed(true, 1.8f);
|
||||
}
|
||||
updatePlaybackButton();
|
||||
});
|
||||
speedItems[0] = playbackSpeedButton.addSubItem(menu_speed_slow, R.drawable.msg_speed_0_5, LocaleController.getString("SpeedSlow", R.string.SpeedSlow));
|
||||
speedItems[1] = playbackSpeedButton.addSubItem(menu_speed_normal, R.drawable.msg_speed_1, LocaleController.getString("SpeedNormal", R.string.SpeedNormal));
|
||||
speedItems[2] = playbackSpeedButton.addSubItem(menu_speed_fast, R.drawable.msg_speed_1_5, LocaleController.getString("SpeedFast", R.string.SpeedFast));
|
||||
speedItems[3] = playbackSpeedButton.addSubItem(menu_speed_veryfast, R.drawable.msg_speed_2, LocaleController.getString("SpeedVeryFast", R.string.SpeedVeryFast));
|
||||
if (AndroidUtilities.density >= 3.0f) {
|
||||
playbackSpeedButton.setPadding(0, 1, 0, 0);
|
||||
}
|
||||
playbackSpeedButton.setAdditionalXOffset(AndroidUtilities.dp(8));
|
||||
playbackSpeedButton.setShowedFromBottom(true);
|
||||
playerLayout.addView(playbackSpeedButton, LayoutHelper.createFrame(36, 36, Gravity.TOP | Gravity.RIGHT, 0, 86, 20, 0));
|
||||
playbackSpeedButton.setOnClickListener(v -> {
|
||||
float currentPlaybackSpeed = MediaController.getInstance().getPlaybackSpeed(true);
|
||||
if (Math.abs(currentPlaybackSpeed - 1.0f) > 0.001f) {
|
||||
MediaController.getInstance().setPlaybackSpeed(true, 1.0f);
|
||||
} else {
|
||||
MediaController.getInstance().setPlaybackSpeed(true, MediaController.getInstance().getFastPlaybackSpeed(true));
|
||||
}
|
||||
updatePlaybackButton();
|
||||
});
|
||||
playbackSpeedButton.setOnLongClickListener(view -> {
|
||||
playbackSpeedButton.toggleSubMenu();
|
||||
return true;
|
||||
});
|
||||
updatePlaybackButton();
|
||||
|
||||
FrameLayout bottomView = new FrameLayout(context) {
|
||||
|
@ -1278,12 +1308,34 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.
|
|||
|
||||
private void updatePlaybackButton() {
|
||||
float currentPlaybackSpeed = MediaController.getInstance().getPlaybackSpeed(true);
|
||||
if (currentPlaybackSpeed > 1) {
|
||||
playbackSpeedButton.setTag(Theme.key_inappPlayerPlayPause);
|
||||
playbackSpeedButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_inappPlayerPlayPause), PorterDuff.Mode.SRC_IN));
|
||||
String key;
|
||||
if (Math.abs(currentPlaybackSpeed - 1.0f) > 0.001f) {
|
||||
key = Theme.key_inappPlayerPlayPause;
|
||||
} else {
|
||||
playbackSpeedButton.setTag(Theme.key_inappPlayerClose);
|
||||
playbackSpeedButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_inappPlayerClose), PorterDuff.Mode.SRC_IN));
|
||||
key = Theme.key_inappPlayerClose;
|
||||
}
|
||||
playbackSpeedButton.setTag(key);
|
||||
float speed = MediaController.getInstance().getFastPlaybackSpeed(true);
|
||||
if (Math.abs(speed - 1.8f) < 0.001f) {
|
||||
playbackSpeedButton.setIcon(R.drawable.voice_mini_2_0);
|
||||
} else if (Math.abs(speed - 1.5f) < 0.001f) {
|
||||
playbackSpeedButton.setIcon(R.drawable.voice_mini_1_5);
|
||||
} else {
|
||||
playbackSpeedButton.setIcon(R.drawable.voice_mini_0_5);
|
||||
}
|
||||
playbackSpeedButton.setIconColor(Theme.getColor(key));
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
playbackSpeedButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(key) & 0x19ffffff, 1, AndroidUtilities.dp(14)));
|
||||
}
|
||||
for (int a = 0; a < speedItems.length; a++) {
|
||||
if (a == 0 && Math.abs(currentPlaybackSpeed - 0.5f) < 0.001f ||
|
||||
a == 1 && Math.abs(currentPlaybackSpeed - 1.0f) < 0.001f ||
|
||||
a == 2 && Math.abs(currentPlaybackSpeed - 1.5f) < 0.001f ||
|
||||
a == 3 && Math.abs(currentPlaybackSpeed - 1.8f) < 0.001f) {
|
||||
speedItems[a].setColors(Theme.getColor(Theme.key_inappPlayerPlayPause), Theme.getColor(Theme.key_inappPlayerPlayPause));
|
||||
} else {
|
||||
speedItems[a].setColors(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1428,9 +1480,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.
|
|||
if (path == null || path.length() == 0) {
|
||||
path = FileLoader.getPathToMessage(messageObject.messageOwner).toString();
|
||||
}
|
||||
MediaController.saveFile(path, parentActivity, 3, fileName, messageObject.getDocument() != null ? messageObject.getDocument().mime_type : "", () -> {
|
||||
BulletinFactory.of((FrameLayout) containerView).createDownloadBulletin(BulletinFactory.FileType.AUDIO).show();
|
||||
});
|
||||
MediaController.saveFile(path, parentActivity, 3, fileName, messageObject.getDocument() != null ? messageObject.getDocument().mime_type : "", () -> BulletinFactory.of((FrameLayout) containerView).createDownloadBulletin(BulletinFactory.FileType.AUDIO).show());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1850,7 +1900,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.
|
|||
durationTextView.setText(duration != 0 ? AndroidUtilities.formatShortDuration(duration) : "-:--");
|
||||
}
|
||||
|
||||
if (duration > 60 * 20) {
|
||||
if (duration > 60 * 10) {
|
||||
playbackSpeedButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
playbackSpeedButton.setVisibility(View.GONE);
|
||||
|
|
|
@ -284,7 +284,7 @@ public final class Bulletin {
|
|||
layout.onExitTransitionEnd();
|
||||
layout.onHide();
|
||||
if (containerLayout != null) {
|
||||
containerLayout.removeView(parentLayout);
|
||||
AndroidUtilities.runOnUIThread(() -> containerLayout.removeView(parentLayout));
|
||||
}
|
||||
layout.onDetach();
|
||||
}
|
||||
|
|
|
@ -788,6 +788,15 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
|
||||
private Drawable lockShadowDrawable;
|
||||
|
||||
private Runnable runEmojiPanelAnimation = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (panelAnimation != null && !panelAnimation.isRunning()) {
|
||||
panelAnimation.start();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public class RecordCircle extends View {
|
||||
|
||||
private float scale;
|
||||
|
@ -1029,9 +1038,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
tooltipWidth = w;
|
||||
}
|
||||
}
|
||||
if (tooltipLayout.getLineCount() > 1) {
|
||||
h += tooltipLayout.getHeight() - tooltipLayout.getLineBottom(0);
|
||||
}
|
||||
}
|
||||
if (tooltipLayout != null && tooltipLayout.getLineCount() > 1) {
|
||||
h += tooltipLayout.getHeight() - tooltipLayout.getLineBottom(0);
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
|
||||
|
||||
|
@ -1860,9 +1869,12 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
return false;
|
||||
}
|
||||
if (isPopupShowing() && event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
boolean rez = false;
|
||||
if (searchingType != 0) {
|
||||
searchingType = 0;
|
||||
emojiView.closeSearch(false);
|
||||
requestFocus();
|
||||
rez = true;
|
||||
}
|
||||
showPopup(AndroidUtilities.usingHardwareInput ? 0 : 2, 0);
|
||||
if (stickersExpanded) {
|
||||
|
@ -1875,7 +1887,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
} else {
|
||||
openKeyboardInternal();
|
||||
}
|
||||
return false;
|
||||
return rez;
|
||||
}
|
||||
try {
|
||||
return super.onTouchEvent(event);
|
||||
|
@ -2307,7 +2319,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
}
|
||||
if (isInScheduleMode()) {
|
||||
AlertsCreator.createScheduleDatePickerDialog(parentActivity, dialog_id, (notify, scheduleDate) -> {
|
||||
SendMessagesHelper.getInstance(currentAccount).sendMessage((String) command, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, notify, scheduleDate, null);
|
||||
SendMessagesHelper.getInstance(currentAccount).sendMessage(command, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, notify, scheduleDate, null);
|
||||
setFieldText("");
|
||||
botCommandsMenuContainer.dismiss();
|
||||
});
|
||||
|
@ -4795,7 +4807,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
}
|
||||
if (stickersExpanded) {
|
||||
setStickersExpanded(false, true, false);
|
||||
if (searchingType != 0) {
|
||||
if (searchingType != 0 && emojiView != null) {
|
||||
emojiView.closeSearch(false);
|
||||
emojiView.hideSearchKeyboard();
|
||||
}
|
||||
|
@ -4875,6 +4887,20 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (searchingType != 0) {
|
||||
searchingType = 0;
|
||||
emojiView.closeSearch(false);
|
||||
|
||||
if (stickersExpanded) {
|
||||
setStickersExpanded(false, true, false);
|
||||
waitingForKeyboardOpenAfterAnimation = true;
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
waitingForKeyboardOpenAfterAnimation = false;
|
||||
openKeyboardInternal();
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
CharSequence[] message = new CharSequence[]{AndroidUtilities.getTrimmedString(messageEditText.getText())};
|
||||
ArrayList<TLRPC.MessageEntity> entities = MediaDataController.getInstance(currentAccount).getEntities(message, supportsSendingNewEntities());
|
||||
if (!TextUtils.equals(message[0], editingMessageObject.messageText) || entities != null && !entities.isEmpty() || entities == null && !editingMessageObject.messageOwner.entities.isEmpty() || editingMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) {
|
||||
|
@ -7681,7 +7707,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
requestLayout();
|
||||
}
|
||||
});
|
||||
panelAnimation.start();
|
||||
AndroidUtilities.runOnUIThread(runEmojiPanelAnimation, 50);
|
||||
notificationsIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(notificationsIndex, null);
|
||||
requestLayout();
|
||||
}
|
||||
|
@ -7725,7 +7751,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
}
|
||||
});
|
||||
notificationsIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(notificationsIndex, null);
|
||||
panelAnimation.start();
|
||||
AndroidUtilities.runOnUIThread(runEmojiPanelAnimation, 50);
|
||||
requestLayout();
|
||||
} else {
|
||||
if (delegate != null) {
|
||||
|
@ -7772,7 +7798,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
}
|
||||
});
|
||||
notificationsIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(notificationsIndex, null);
|
||||
panelAnimation.start();
|
||||
AndroidUtilities.runOnUIThread(runEmojiPanelAnimation, 50);
|
||||
requestLayout();
|
||||
} else {
|
||||
if (!waitingForKeyboardOpen) {
|
||||
|
@ -8064,7 +8090,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
NotificationCenter.getInstance(currentAccount).onAnimationFinish(notificationsIndex);
|
||||
}
|
||||
});
|
||||
panelAnimation.start();
|
||||
AndroidUtilities.runOnUIThread(runEmojiPanelAnimation, 50);
|
||||
notificationsIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(notificationsIndex, null);
|
||||
requestLayout();
|
||||
}
|
||||
|
@ -8106,6 +8132,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
return emojiPadding;
|
||||
}
|
||||
|
||||
public int getVisibleEmojiPadding() {
|
||||
return emojiViewVisible ? emojiPadding : 0;
|
||||
}
|
||||
|
||||
private MessageObject getThreadMessage() {
|
||||
return parentFragment != null ? parentFragment.getThreadMessage() : null;
|
||||
}
|
||||
|
@ -9178,4 +9208,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void runEmojiPanelAnimation() {
|
||||
AndroidUtilities.cancelRunOnUIThread(runEmojiPanelAnimation);
|
||||
runEmojiPanelAnimation.run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -629,8 +629,10 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou
|
|||
chatActivity = null;
|
||||
type = 4;
|
||||
}
|
||||
AndroidUtilities.hideKeyboard(parentAlert.baseFragment.getFragmentView().findFocus());
|
||||
AndroidUtilities.hideKeyboard(parentAlert.getContainer().findFocus());
|
||||
if (!parentAlert.delegate.needEnterComment()) {
|
||||
AndroidUtilities.hideKeyboard(parentAlert.baseFragment.getFragmentView().findFocus());
|
||||
AndroidUtilities.hideKeyboard(parentAlert.getContainer().findFocus());
|
||||
}
|
||||
PhotoViewer.getInstance().openPhotoForSelect(arrayList, position, type, false, photoViewerProvider, chatActivity);
|
||||
} else {
|
||||
if (SharedConfig.inappCamera) {
|
||||
|
@ -1426,7 +1428,7 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou
|
|||
return false;
|
||||
}
|
||||
int locked = Settings.System.getInt(parentAlert.baseFragment.getParentActivity().getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0);
|
||||
return true;//sameTakePictureOrientation || locked == 1;
|
||||
return sameTakePictureOrientation || locked == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.widget.TextView;
|
|||
import androidx.core.widget.NestedScrollView;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.ChatObject;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
|
@ -123,8 +122,10 @@ public class ClearHistoryAlert extends BottomSheet {
|
|||
newTimer = currentTimer = 0;
|
||||
} else if (ttl == 24 * 60 * 60) {
|
||||
newTimer = currentTimer = 1;
|
||||
} else {
|
||||
} else if (ttl == 7 * 24 * 60 * 60) {
|
||||
newTimer = currentTimer = 2;
|
||||
} else {
|
||||
newTimer = currentTimer = 3;
|
||||
}
|
||||
|
||||
shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate();
|
||||
|
@ -345,7 +346,8 @@ public class ClearHistoryAlert extends BottomSheet {
|
|||
String[] strings = new String[]{
|
||||
LocaleController.getString("AutoDeleteNever", R.string.AutoDeleteNever),
|
||||
LocaleController.getString("AutoDelete24Hours", R.string.AutoDelete24Hours),
|
||||
LocaleController.getString("AutoDelete7Days", R.string.AutoDelete7Days)
|
||||
LocaleController.getString("AutoDelete7Days", R.string.AutoDelete7Days),
|
||||
LocaleController.getString("AutoDelete1Month", R.string.AutoDelete1Month)
|
||||
};
|
||||
slideChooseView.setOptions(currentTimer, strings);
|
||||
linearLayout.addView(slideChooseView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 8, 0, 0));
|
||||
|
@ -379,7 +381,10 @@ public class ClearHistoryAlert extends BottomSheet {
|
|||
dismissedDelayed = true;
|
||||
int time;
|
||||
int action;
|
||||
if (newTimer == 2) {
|
||||
if (newTimer == 3) {
|
||||
time = 31 * 24 * 60 * 60;
|
||||
action = UndoView.ACTION_AUTO_DELETE_ON;
|
||||
} else if (newTimer == 2) {
|
||||
time = 7 * 24 * 60 * 60;
|
||||
action = UndoView.ACTION_AUTO_DELETE_ON;
|
||||
} else if (newTimer == 1) {
|
||||
|
|
|
@ -89,6 +89,9 @@ public class CounterView extends View {
|
|||
if (count > 0) {
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (Math.abs(count - currentCount) > 99) {
|
||||
animated = false;
|
||||
}
|
||||
if (!animated) {
|
||||
currentCount = count;
|
||||
if (count == 0) {
|
||||
|
|
|
@ -764,12 +764,11 @@ public class EditTextBoldCursor extends EditText {
|
|||
private boolean updateCursorPosition() {
|
||||
final Layout layout = getLayout();
|
||||
final int offset = getSelectionStart();
|
||||
if (offset != lastOffset || lastText != layout.getText()) {
|
||||
final int line = layout.getLineForOffset(offset);
|
||||
final int top = layout.getLineTop(line);
|
||||
final int bottom = layout.getLineTop(line + 1);
|
||||
updateCursorPosition(top, bottom, layout.getPrimaryHorizontal(offset));
|
||||
}
|
||||
final int line = layout.getLineForOffset(offset);
|
||||
final int top = layout.getLineTop(line);
|
||||
final int bottom = layout.getLineTop(line + 1);
|
||||
updateCursorPosition(top, bottom, layout.getPrimaryHorizontal(offset));
|
||||
|
||||
lastText = layout.getText();
|
||||
lastOffset = offset;
|
||||
return true;
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.telegram.messenger.ApplicationLoader;
|
|||
import org.telegram.messenger.BringAppForegroundService;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.MessageObject;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.Utilities;
|
||||
|
@ -60,6 +61,7 @@ import org.telegram.messenger.browser.Browser;
|
|||
import org.telegram.ui.ActionBar.BottomSheet;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.LaunchActivity;
|
||||
import org.telegram.ui.PhotoViewer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
@ -217,17 +219,23 @@ public class EmbedBottomSheet extends BottomSheet {
|
|||
@SuppressLint("StaticFieldLeak")
|
||||
private static EmbedBottomSheet instance;
|
||||
|
||||
public static void show(Context context, String title, String description, String originalUrl, final String url, int w, int h, boolean keyboardVisible) {
|
||||
show(context, title, description, originalUrl, url, w, h, -1, keyboardVisible);
|
||||
public static void show(Activity activity, MessageObject message, PhotoViewer.PhotoViewerProvider photoViewerProvider, String title, String description, String originalUrl, final String url, int w, int h, boolean keyboardVisible) {
|
||||
show(activity, message, photoViewerProvider, title, description, originalUrl, url, w, h, -1, keyboardVisible);
|
||||
}
|
||||
|
||||
public static void show(Context context, String title, String description, String originalUrl, final String url, int w, int h, int seekTime, boolean keyboardVisible) {
|
||||
public static void show(Activity activity, MessageObject message, PhotoViewer.PhotoViewerProvider photoViewerProvider, String title, String description, String originalUrl, final String url, int w, int h, int seekTime, boolean keyboardVisible) {
|
||||
if (instance != null) {
|
||||
instance.destroy();
|
||||
}
|
||||
EmbedBottomSheet sheet = new EmbedBottomSheet(context, title, description, originalUrl, url, w, h, seekTime);
|
||||
sheet.setCalcMandatoryInsets(keyboardVisible);
|
||||
sheet.show();
|
||||
String youtubeId = message != null && message.messageOwner.media != null && message.messageOwner.media.webpage != null ? WebPlayerView.getYouTubeVideoId(url) : null;
|
||||
if (youtubeId != null) {
|
||||
PhotoViewer.getInstance().setParentActivity(activity);
|
||||
PhotoViewer.getInstance().openPhoto(message, seekTime, null, 0, 0, photoViewerProvider);
|
||||
} else {
|
||||
EmbedBottomSheet sheet = new EmbedBottomSheet(activity, title, description, originalUrl, url, w, h, seekTime);
|
||||
sheet.setCalcMandatoryInsets(keyboardVisible);
|
||||
sheet.show();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
|
@ -259,10 +267,8 @@ public class EmbedBottomSheet extends BottomSheet {
|
|||
fullscreenVideoContainer.setFitsSystemWindows(true);
|
||||
}
|
||||
fullscreenVideoContainer.setOnTouchListener((v, event) -> true);
|
||||
|
||||
container.addView(fullscreenVideoContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
fullscreenVideoContainer.setVisibility(View.INVISIBLE);
|
||||
fullscreenVideoContainer.setOnTouchListener((v, event) -> true);
|
||||
|
||||
containerLayout = new FrameLayout(context) {
|
||||
@Override
|
||||
|
|
|
@ -66,6 +66,8 @@ import org.telegram.messenger.UserObject;
|
|||
import org.telegram.messenger.voip.VoIPService;
|
||||
import org.telegram.tgnet.ConnectionsManager;
|
||||
import org.telegram.tgnet.TLRPC;
|
||||
import org.telegram.ui.ActionBar.ActionBarMenuItem;
|
||||
import org.telegram.ui.ActionBar.ActionBarMenuSubItem;
|
||||
import org.telegram.ui.ActionBar.AlertDialog;
|
||||
import org.telegram.ui.ActionBar.BaseFragment;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
|
@ -96,7 +98,8 @@ public class FragmentContextView extends FrameLayout implements NotificationCent
|
|||
private RLottieImageView muteButton;
|
||||
private RLottieDrawable muteDrawable;
|
||||
private ImageView closeButton;
|
||||
private ImageView playbackSpeedButton;
|
||||
private ActionBarMenuItem playbackSpeedButton;
|
||||
private ActionBarMenuSubItem[] speedItems = new ActionBarMenuSubItem[4];
|
||||
private FragmentContextView additionalContextView;
|
||||
private TextView joinButton;
|
||||
|
||||
|
@ -170,6 +173,11 @@ public class FragmentContextView extends FrameLayout implements NotificationCent
|
|||
private boolean checkPlayerAfterAnimation;
|
||||
private boolean checkImportAfterAnimation;
|
||||
|
||||
private final static int menu_speed_slow = 1;
|
||||
private final static int menu_speed_normal = 2;
|
||||
private final static int menu_speed_fast = 3;
|
||||
private final static int menu_speed_veryfast = 4;
|
||||
|
||||
@Override
|
||||
public void onAudioSettingsChanged() {
|
||||
boolean newMuted = VoIPService.getSharedInstance() != null && VoIPService.getSharedInstance().isMicMute();
|
||||
|
@ -351,22 +359,49 @@ public class FragmentContextView extends FrameLayout implements NotificationCent
|
|||
joinButton.setOnClickListener(v -> FragmentContextView.this.callOnClick());
|
||||
|
||||
if (!location) {
|
||||
playbackSpeedButton = new ImageView(context);
|
||||
playbackSpeedButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||
playbackSpeedButton.setImageResource(R.drawable.voice2x);
|
||||
playbackSpeedButton = new ActionBarMenuItem(context, null, 0, Theme.getColor(Theme.key_dialogTextBlack));
|
||||
playbackSpeedButton.setLongClickEnabled(false);
|
||||
playbackSpeedButton.setShowSubmenuByMove(false);
|
||||
playbackSpeedButton.setContentDescription(LocaleController.getString("AccDescrPlayerSpeed", R.string.AccDescrPlayerSpeed));
|
||||
if (AndroidUtilities.density >= 3.0f) {
|
||||
playbackSpeedButton.setPadding(0, 1, 0, 0);
|
||||
}
|
||||
addView(playbackSpeedButton, LayoutHelper.createFrame(36, 36, Gravity.TOP | Gravity.RIGHT, 0, 0, 36, 0));
|
||||
playbackSpeedButton.setOnClickListener(v -> {
|
||||
float currentPlaybackSpeed = MediaController.getInstance().getPlaybackSpeed(isMusic);
|
||||
if (currentPlaybackSpeed > 1) {
|
||||
playbackSpeedButton.setDelegate(id -> {
|
||||
float oldSpeed = MediaController.getInstance().getPlaybackSpeed(isMusic);
|
||||
if (id == menu_speed_slow) {
|
||||
MediaController.getInstance().setPlaybackSpeed(isMusic, 0.5f);
|
||||
} else if (id == menu_speed_normal) {
|
||||
MediaController.getInstance().setPlaybackSpeed(isMusic, 1.0f);
|
||||
} else if (id == menu_speed_fast) {
|
||||
MediaController.getInstance().setPlaybackSpeed(isMusic, 1.5f);
|
||||
} else {
|
||||
MediaController.getInstance().setPlaybackSpeed(isMusic, 1.8f);
|
||||
}
|
||||
playbackSpeedChanged(currentPlaybackSpeed <= 1);
|
||||
float newSpeed = MediaController.getInstance().getPlaybackSpeed(isMusic);
|
||||
if (oldSpeed != newSpeed) {
|
||||
playbackSpeedChanged(newSpeed);
|
||||
}
|
||||
updatePlaybackButton();
|
||||
});
|
||||
speedItems[0] = playbackSpeedButton.addSubItem(menu_speed_slow, R.drawable.msg_speed_0_5, LocaleController.getString("SpeedSlow", R.string.SpeedSlow));
|
||||
speedItems[1] = playbackSpeedButton.addSubItem(menu_speed_normal, R.drawable.msg_speed_1, LocaleController.getString("SpeedNormal", R.string.SpeedNormal));
|
||||
speedItems[2] = playbackSpeedButton.addSubItem(menu_speed_fast, R.drawable.msg_speed_1_5, LocaleController.getString("SpeedFast", R.string.SpeedFast));
|
||||
speedItems[3] = playbackSpeedButton.addSubItem(menu_speed_veryfast, R.drawable.msg_speed_2, LocaleController.getString("SpeedVeryFast", R.string.SpeedVeryFast));
|
||||
if (AndroidUtilities.density >= 3.0f) {
|
||||
playbackSpeedButton.setPadding(0, 1, 0, 0);
|
||||
}
|
||||
playbackSpeedButton.setAdditionalXOffset(AndroidUtilities.dp(8));
|
||||
addView(playbackSpeedButton, LayoutHelper.createFrame(36, 36, Gravity.TOP | Gravity.RIGHT, 0, 0, 36, 0));
|
||||
playbackSpeedButton.setOnClickListener(v -> {
|
||||
float currentPlaybackSpeed = MediaController.getInstance().getPlaybackSpeed(isMusic);
|
||||
float newSpeed;
|
||||
if (Math.abs(currentPlaybackSpeed - 1.0f) > 0.001f) {
|
||||
MediaController.getInstance().setPlaybackSpeed(isMusic, newSpeed = 1.0f);
|
||||
} else {
|
||||
MediaController.getInstance().setPlaybackSpeed(isMusic, newSpeed = MediaController.getInstance().getFastPlaybackSpeed(isMusic));
|
||||
}
|
||||
playbackSpeedChanged(newSpeed);
|
||||
});
|
||||
playbackSpeedButton.setOnLongClickListener(view -> {
|
||||
playbackSpeedButton.toggleSubMenu();
|
||||
return true;
|
||||
});
|
||||
updatePlaybackButton();
|
||||
}
|
||||
|
@ -653,15 +688,33 @@ public class FragmentContextView extends FrameLayout implements NotificationCent
|
|||
}
|
||||
float currentPlaybackSpeed = MediaController.getInstance().getPlaybackSpeed(isMusic);
|
||||
String key;
|
||||
if (currentPlaybackSpeed > 1) {
|
||||
if (Math.abs(currentPlaybackSpeed - 1.0f) > 0.001f) {
|
||||
key = Theme.key_inappPlayerPlayPause;
|
||||
} else {
|
||||
key = Theme.key_inappPlayerClose;
|
||||
}
|
||||
playbackSpeedButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(key), PorterDuff.Mode.SRC_IN));
|
||||
float speed = MediaController.getInstance().getFastPlaybackSpeed(isMusic);
|
||||
if (Math.abs(speed - 1.8f) < 0.001f) {
|
||||
playbackSpeedButton.setIcon(R.drawable.voice_mini_2_0);
|
||||
} else if (Math.abs(speed - 1.5f) < 0.001f) {
|
||||
playbackSpeedButton.setIcon(R.drawable.voice_mini_1_5);
|
||||
} else {
|
||||
playbackSpeedButton.setIcon(R.drawable.voice_mini_0_5);
|
||||
}
|
||||
playbackSpeedButton.setIconColor(Theme.getColor(key));
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
playbackSpeedButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(key) & 0x19ffffff, 1, AndroidUtilities.dp(14)));
|
||||
}
|
||||
for (int a = 0; a < speedItems.length; a++) {
|
||||
if (a == 0 && Math.abs(currentPlaybackSpeed - 0.5f) < 0.001f ||
|
||||
a == 1 && Math.abs(currentPlaybackSpeed - 1.0f) < 0.001f ||
|
||||
a == 2 && Math.abs(currentPlaybackSpeed - 1.5f) < 0.001f ||
|
||||
a == 3 && Math.abs(currentPlaybackSpeed - 1.8f) < 0.001f) {
|
||||
speedItems[a].setColors(Theme.getColor(Theme.key_inappPlayerPlayPause), Theme.getColor(Theme.key_inappPlayerPlayPause));
|
||||
} else {
|
||||
speedItems[a].setColors(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAdditionalContextView(FragmentContextView contextView) {
|
||||
|
@ -727,7 +780,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent
|
|||
}
|
||||
}
|
||||
|
||||
protected void playbackSpeedChanged(boolean enabled) {
|
||||
protected void playbackSpeedChanged(float value) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package org.telegram.ui.Components;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.view.View;
|
||||
|
||||
public class HideViewAfterAnimation extends AnimatorListenerAdapter {
|
||||
|
||||
private final View view;
|
||||
public HideViewAfterAnimation(View view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ import android.content.Context;
|
|||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
|
@ -57,6 +58,8 @@ import android.view.animation.DecelerateInterpolator;
|
|||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
|
@ -68,6 +71,7 @@ import org.telegram.messenger.FileLog;
|
|||
import org.telegram.messenger.ImageReceiver;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.MediaController;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.NotificationCenter;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.SharedConfig;
|
||||
|
@ -84,6 +88,7 @@ import org.telegram.tgnet.ConnectionsManager;
|
|||
import org.telegram.tgnet.TLRPC;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.ChatActivity;
|
||||
import org.telegram.ui.Components.voip.CellFlickerDrawable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -154,6 +159,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
private TextureView textureView;
|
||||
private BackupImageView textureOverlayView;
|
||||
private CameraSession cameraSession;
|
||||
private boolean needDrawFlickerStub;
|
||||
|
||||
private float panTranslationY;
|
||||
private float animationTranslationY;
|
||||
|
@ -214,6 +220,9 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
boolean maybePinchToZoomTouchMode;
|
||||
|
||||
private int pointerId1, pointerId2;
|
||||
private int textureViewSize;
|
||||
private boolean isMessageTransition;
|
||||
private boolean updateTextureViewSize;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
public InstantCameraView(Context context, ChatActivity parentFragment) {
|
||||
|
@ -256,7 +265,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setOval(0, 0, AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize);
|
||||
outline.setOval(0, 0, textureViewSize, textureViewSize);
|
||||
}
|
||||
});
|
||||
cameraContainer.setClipToOutline(true);
|
||||
|
@ -296,7 +305,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
cameraContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
|
||||
addView(cameraContainer, new FrameLayout.LayoutParams(AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize, Gravity.CENTER));
|
||||
addView(cameraContainer, new FrameLayout.LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER));
|
||||
|
||||
switchCameraButton = new ImageView(context);
|
||||
switchCameraButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||
|
@ -323,16 +332,58 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
muteImageView.setImageResource(R.drawable.video_mute);
|
||||
muteImageView.setAlpha(0.0f);
|
||||
addView(muteImageView, LayoutHelper.createFrame(48, 48, Gravity.CENTER));
|
||||
((LayoutParams) muteImageView.getLayoutParams()).topMargin = AndroidUtilities.roundMessageSize / 2 - AndroidUtilities.dp(24);
|
||||
|
||||
textureOverlayView = new BackupImageView(getContext());
|
||||
textureOverlayView.setRoundRadius(AndroidUtilities.roundMessageSize / 2);
|
||||
addView(textureOverlayView, new FrameLayout.LayoutParams(AndroidUtilities.roundMessageSize, AndroidUtilities.roundMessageSize, Gravity.CENTER));
|
||||
Paint blackoutPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
blackoutPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, 40));
|
||||
textureOverlayView = new BackupImageView(getContext()) {
|
||||
|
||||
CellFlickerDrawable flickerDrawable = new CellFlickerDrawable();
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (needDrawFlickerStub) {
|
||||
flickerDrawable.setParentWidth(textureViewSize);
|
||||
AndroidUtilities.rectTmp.set(0, 0, textureViewSize, textureViewSize);
|
||||
float rad = AndroidUtilities.rectTmp.width() / 2f;
|
||||
canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, blackoutPaint);
|
||||
AndroidUtilities.rectTmp.inset(AndroidUtilities.dp(1), AndroidUtilities.dp(1));
|
||||
flickerDrawable.draw(canvas, AndroidUtilities.rectTmp, rad);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
};
|
||||
addView(textureOverlayView, new FrameLayout.LayoutParams(AndroidUtilities.roundPlayingMessageSize, AndroidUtilities.roundPlayingMessageSize, Gravity.CENTER));
|
||||
|
||||
setVisibility(INVISIBLE);
|
||||
blurBehindDrawable = new BlurBehindDrawable(parentView, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (updateTextureViewSize) {
|
||||
int newSize;
|
||||
if (MeasureSpec.getSize(heightMeasureSpec) > MeasureSpec.getSize(widthMeasureSpec) * 1.3f) {
|
||||
newSize = AndroidUtilities.roundPlayingMessageSize;
|
||||
} else {
|
||||
newSize = AndroidUtilities.roundMessageSize;
|
||||
}
|
||||
if (newSize != textureViewSize) {
|
||||
textureViewSize = newSize;
|
||||
textureOverlayView.getLayoutParams().width = textureOverlayView.getLayoutParams().height = textureViewSize;
|
||||
cameraContainer.getLayoutParams().width = cameraContainer.getLayoutParams().height = textureViewSize;
|
||||
((LayoutParams) muteImageView.getLayoutParams()).topMargin = textureViewSize / 2 - AndroidUtilities.dp(24);
|
||||
textureOverlayView.setRoundRadius(textureViewSize / 2);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
cameraContainer.invalidateOutline();
|
||||
}
|
||||
}
|
||||
updateTextureViewSize = false;
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
private boolean checkPointerIds(MotionEvent ev) {
|
||||
if (ev.getPointerCount() < 2) {
|
||||
return false;
|
||||
|
@ -420,9 +471,13 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
int x1 = (int) x - AndroidUtilities.dp(3);
|
||||
int y1 = (int) y - AndroidUtilities.dp(2);
|
||||
canvas.save();
|
||||
canvas.scale(cameraContainer.getScaleX(), cameraContainer.getScaleY(), x1 + AndroidUtilities.roundMessageSize / 2 + AndroidUtilities.dp(3), y1 + AndroidUtilities.roundMessageSize / 2 + AndroidUtilities.dp(3));
|
||||
if (isMessageTransition) {
|
||||
canvas.scale(cameraContainer.getScaleX(), cameraContainer.getScaleY(), x, y);
|
||||
} else {
|
||||
canvas.scale(cameraContainer.getScaleX(), cameraContainer.getScaleY(), x + textureViewSize / 2f, y + textureViewSize / 2f);
|
||||
}
|
||||
Theme.chat_roundVideoShadow.setAlpha((int) (cameraContainer.getAlpha() * 255));
|
||||
Theme.chat_roundVideoShadow.setBounds(x1, y1, x1 + AndroidUtilities.roundMessageSize + AndroidUtilities.dp(6), y1 + AndroidUtilities.roundMessageSize + AndroidUtilities.dp(6));
|
||||
Theme.chat_roundVideoShadow.setBounds(x1, y1, x1 + textureViewSize + AndroidUtilities.dp(6), y1 + textureViewSize + AndroidUtilities.dp(6));
|
||||
Theme.chat_roundVideoShadow.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
@ -468,6 +523,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
|
||||
switchCameraButton.setImageResource(R.drawable.camera_revert1);
|
||||
textureOverlayView.setAlpha(1.0f);
|
||||
textureOverlayView.invalidate();
|
||||
if (lastBitmap == null) {
|
||||
try {
|
||||
File file = new File(ApplicationLoader.getFilesDirFixed(), "icthumb.jpg");
|
||||
|
@ -491,6 +547,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
encryptedFile = null;
|
||||
key = null;
|
||||
iv = null;
|
||||
needDrawFlickerStub = true;
|
||||
|
||||
if (!initCamera()) {
|
||||
return;
|
||||
|
@ -546,6 +603,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
});
|
||||
cameraContainer.addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
|
||||
updateTextureViewSize = true;
|
||||
setVisibility(VISIBLE);
|
||||
|
||||
startAnimation(true);
|
||||
|
@ -664,7 +722,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
long endTime = videoEditedInfo.endTime >= 0 ? videoEditedInfo.endTime : videoEditedInfo.estimatedDuration;
|
||||
videoEditedInfo.estimatedDuration = endTime - startTime;
|
||||
videoEditedInfo.estimatedSize = Math.max(1, (long) (size * (videoEditedInfo.estimatedDuration / totalDuration)));
|
||||
videoEditedInfo.bitrate = 400000;
|
||||
videoEditedInfo.bitrate = 1000000;
|
||||
if (videoEditedInfo.startTime > 0) {
|
||||
videoEditedInfo.startTime *= 1000;
|
||||
}
|
||||
|
@ -718,7 +776,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
private void saveLastCameraBitmap() {
|
||||
Bitmap bitmap = textureView.getBitmap();
|
||||
if (bitmap != null && bitmap.getPixel(0, 0) != 0) {
|
||||
lastBitmap = Bitmap.createScaledBitmap(textureView.getBitmap(), 80, 80, true);
|
||||
lastBitmap = Bitmap.createScaledBitmap(textureView.getBitmap(), 50, 50, true);
|
||||
if (lastBitmap != null) {
|
||||
Utilities.blurBitmap(lastBitmap, 7, 1, lastBitmap.getWidth(), lastBitmap.getHeight(), lastBitmap.getRowBytes());
|
||||
try {
|
||||
|
@ -793,6 +851,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
private void switchCamera() {
|
||||
saveLastCameraBitmap();
|
||||
if (lastBitmap != null) {
|
||||
needDrawFlickerStub = false;
|
||||
textureOverlayView.setImageBitmap(lastBitmap);
|
||||
textureOverlayView.setAlpha(1f);
|
||||
}
|
||||
|
@ -859,7 +918,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
Size preview = previewSizes.get(a);
|
||||
for (int b = pictureSizes.size() - 1; b >= 0; b--) {
|
||||
Size picture = pictureSizes.get(b);
|
||||
if (preview.mWidth >= 240 && preview.mHeight >= 240 && preview.mWidth == picture.mWidth && preview.mHeight == picture.mHeight) {
|
||||
if (preview.mWidth >= 360 && preview.mHeight >= 360 && preview.mWidth == picture.mWidth && preview.mHeight == picture.mHeight) {
|
||||
previewSize = preview;
|
||||
pictureSize = picture;
|
||||
found = true;
|
||||
|
@ -981,6 +1040,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
return textureView;
|
||||
}
|
||||
|
||||
public void setIsMessageTransition(boolean isMessageTransition) {
|
||||
this.isMessageTransition = isMessageTransition;
|
||||
}
|
||||
|
||||
public class CameraGLThread extends DispatchQueue {
|
||||
|
||||
private final static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
|
@ -1600,19 +1663,8 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
};
|
||||
|
||||
public void startRecording(File outputFile, android.opengl.EGLContext sharedContext) {
|
||||
int resolution;
|
||||
int bitrate;
|
||||
String model = Build.DEVICE;
|
||||
if (model == null) {
|
||||
model = "";
|
||||
}
|
||||
if (model.startsWith("zeroflte") || model.startsWith("zenlte")) {
|
||||
resolution = 320;
|
||||
bitrate = 600000;
|
||||
} else {
|
||||
resolution = 240;
|
||||
bitrate = 400000;
|
||||
}
|
||||
int resolution = MessagesController.getInstance(currentAccount).roundVideoSize;
|
||||
int bitrate = MessagesController.getInstance(currentAccount).roundVideoBitrate * 1024;
|
||||
|
||||
videoFile = outputFile;
|
||||
videoWidth = resolution;
|
||||
|
@ -1982,8 +2034,8 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
videoEditedInfo.iv = iv;
|
||||
videoEditedInfo.estimatedSize = Math.max(1, size);
|
||||
videoEditedInfo.framerate = 25;
|
||||
videoEditedInfo.resultWidth = videoEditedInfo.originalWidth = 240;
|
||||
videoEditedInfo.resultHeight = videoEditedInfo.originalHeight = 240;
|
||||
videoEditedInfo.resultWidth = videoEditedInfo.originalWidth = 360;
|
||||
videoEditedInfo.resultHeight = videoEditedInfo.originalHeight = 360;
|
||||
videoEditedInfo.originalPath = videoFile.getAbsolutePath();
|
||||
if (send == 1) {
|
||||
if (baseFragment.isInScheduleMode()) {
|
||||
|
@ -2105,7 +2157,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
audioFormat.setString(MediaFormat.KEY_MIME, AUDIO_MIME_TYPE);
|
||||
audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
|
||||
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
|
||||
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, 32000);
|
||||
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, MessagesController.getInstance(currentAccount).roundAudioBitrate * 1024);
|
||||
audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 2048 * AudioBufferInfo.MAX_SAMPLES);
|
||||
|
||||
audioEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
|
||||
|
@ -2460,6 +2512,10 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
|
|||
}
|
||||
if (imageReceiver != null) {
|
||||
canvas.save();
|
||||
if (imageReceiver.getImageWidth() != textureViewSize) {
|
||||
float s = textureViewSize / imageReceiver.getImageWidth();
|
||||
canvas.scale(s, s);
|
||||
}
|
||||
canvas.translate(-imageReceiver.getImageX(), -imageReceiver.getImageY());
|
||||
float oldAlpha = imageReceiver.getAlpha();
|
||||
imageReceiver.setAlpha(imageProgress);
|
||||
|
|
|
@ -897,9 +897,9 @@ public class PasscodeView extends FrameLayout {
|
|||
numbersFrameLayout.setVisibility(INVISIBLE);
|
||||
}
|
||||
AndroidUtilities.hideKeyboard(passwordEditText);
|
||||
AndroidUtilities.cancelRunOnUIThread(checkRunnable);
|
||||
AndroidUtilities.runOnUIThread(checkRunnable, 100);
|
||||
}
|
||||
AndroidUtilities.cancelRunOnUIThread(checkRunnable);
|
||||
AndroidUtilities.runOnUIThread(checkRunnable, 100);
|
||||
} else {
|
||||
AndroidUtilities.cancelRunOnUIThread(checkRunnable);
|
||||
if (passwordFrameLayout.getVisibility() != VISIBLE) {
|
||||
|
|
|
@ -0,0 +1,376 @@
|
|||
package org.telegram.ui.Components;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Canvas;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.BringAppForegroundService;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.messenger.browser.Browser;
|
||||
import org.telegram.tgnet.TLRPC;
|
||||
import org.telegram.ui.PhotoViewer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PhotoViewerWebView extends FrameLayout {
|
||||
|
||||
private int currentAccount = UserConfig.selectedAccount;
|
||||
private PipVideoView pipVideoView;
|
||||
|
||||
private WebView webView;
|
||||
private View progressBarBlackBackground;
|
||||
private RadialProgressView progressBar;
|
||||
private View pipItem;
|
||||
|
||||
private boolean isYouTube;
|
||||
private TLRPC.WebPage currentWebpage;
|
||||
|
||||
private float playbackSpeed;
|
||||
private boolean setPlaybackSpeed;
|
||||
|
||||
private class YoutubeProxy {
|
||||
@JavascriptInterface
|
||||
public void postEvent(final String eventName, final String eventData) {
|
||||
if ("loaded".equals(eventName)) {
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
progressBarBlackBackground.setVisibility(View.INVISIBLE);
|
||||
if (setPlaybackSpeed) {
|
||||
setPlaybackSpeed = false;
|
||||
setPlaybackSpeed(playbackSpeed);
|
||||
}
|
||||
pipItem.setEnabled(true);
|
||||
pipItem.setAlpha(1.0f);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String youtubeFrame = "<!DOCTYPE html><html><head><style>" +
|
||||
"body { margin: 0; width:100%%; height:100%%; background-color:#000; }" +
|
||||
"html { width:100%%; height:100%%; background-color:#000; }" +
|
||||
".embed-container iframe," +
|
||||
".embed-container object," +
|
||||
" .embed-container embed {" +
|
||||
" position: absolute;" +
|
||||
" top: 0;" +
|
||||
" left: 0;" +
|
||||
" width: 100%% !important;" +
|
||||
" height: 100%% !important;" +
|
||||
" }" +
|
||||
" </style></head><body>" +
|
||||
" <div class=\"embed-container\">" +
|
||||
" <div id=\"player\"></div>" +
|
||||
" </div>" +
|
||||
" <script src=\"https://www.youtube.com/iframe_api\"></script>" +
|
||||
" <script>" +
|
||||
" var player;" +
|
||||
" var posted = false;" +
|
||||
" YT.ready(function() {" +
|
||||
" player = new YT.Player(\"player\", {" +
|
||||
" \"width\" : \"100%%\"," +
|
||||
" \"events\" : {" +
|
||||
" \"onReady\" : \"onReady\"," +
|
||||
" \"onError\" : \"onError\"," +
|
||||
" \"onStateChange\" : \"onStateChange\"," +
|
||||
" }," +
|
||||
" \"videoId\" : \"%1$s\"," +
|
||||
" \"height\" : \"100%%\"," +
|
||||
" \"playerVars\" : {" +
|
||||
" \"start\" : %2$d," +
|
||||
" \"rel\" : 1," +
|
||||
" \"showinfo\" : 0," +
|
||||
" \"modestbranding\" : 0," +
|
||||
" \"iv_load_policy\" : 3," +
|
||||
" \"autohide\" : 1," +
|
||||
" \"autoplay\" : 1," +
|
||||
" \"cc_load_policy\" : 1," +
|
||||
" \"playsinline\" : 1," +
|
||||
" \"controls\" : 1" +
|
||||
" }" +
|
||||
" });" +
|
||||
" player.setSize(window.innerWidth, window.innerHeight);" +
|
||||
" });" +
|
||||
" function setPlaybackSpeed(speed) { " +
|
||||
" player.setPlaybackRate(speed);" +
|
||||
" }" +
|
||||
" function onError(event) {" +
|
||||
" if (!posted) {" +
|
||||
" if (window.YoutubeProxy !== undefined) {" +
|
||||
" YoutubeProxy.postEvent(\"loaded\", null); " +
|
||||
" }" +
|
||||
" posted = true;" +
|
||||
" }" +
|
||||
" }" +
|
||||
" function onStateChange(event) {" +
|
||||
" if (event.data == YT.PlayerState.PLAYING && !posted) {" +
|
||||
" if (window.YoutubeProxy !== undefined) {" +
|
||||
" YoutubeProxy.postEvent(\"loaded\", null); " +
|
||||
" }" +
|
||||
" posted = true;" +
|
||||
" }" +
|
||||
" }" +
|
||||
" function onReady(event) {" +
|
||||
" player.playVideo();" +
|
||||
" }" +
|
||||
" window.onresize = function() {" +
|
||||
" player.setSize(window.innerWidth, window.innerHeight);" +
|
||||
" player.playVideo();" +
|
||||
" }" +
|
||||
" </script>" +
|
||||
"</body>" +
|
||||
"</html>";
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
public PhotoViewerWebView(Context context, View pip) {
|
||||
super(context);
|
||||
|
||||
pipItem = pip;
|
||||
webView = new WebView(context) {
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
processTouch(event);
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
};
|
||||
webView.getSettings().setJavaScriptEnabled(true);
|
||||
webView.getSettings().setDomStorageEnabled(true);
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
|
||||
CookieManager cookieManager = CookieManager.getInstance();
|
||||
cookieManager.setAcceptThirdPartyCookies(webView, true);
|
||||
}
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public void onLoadResource(WebView view, String url) {
|
||||
super.onLoadResource(view, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
if (!isYouTube || Build.VERSION.SDK_INT < 17) {
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
progressBarBlackBackground.setVisibility(View.INVISIBLE);
|
||||
pipItem.setEnabled(true);
|
||||
pipItem.setAlpha(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (isYouTube) {
|
||||
Browser.openUrl(view.getContext(), url);
|
||||
return true;
|
||||
}
|
||||
return super.shouldOverrideUrlLoading(view, url);
|
||||
}
|
||||
});
|
||||
|
||||
addView(webView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT));
|
||||
|
||||
progressBarBlackBackground = new View(context) {
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
drawBlackBackground(canvas, getMeasuredWidth(), getMeasuredHeight());
|
||||
}
|
||||
};
|
||||
progressBarBlackBackground.setBackgroundColor(0xff000000);
|
||||
progressBarBlackBackground.setVisibility(View.INVISIBLE);
|
||||
addView(progressBarBlackBackground, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
|
||||
progressBar = new RadialProgressView(context);
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
addView(progressBar, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER));
|
||||
}
|
||||
|
||||
private void runJsCode(String code) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
webView.evaluateJavascript(code, null);
|
||||
} else {
|
||||
try {
|
||||
webView.loadUrl("javascript:" + code);
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void processTouch(MotionEvent event) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (webView.getParent() == this) {
|
||||
int w = currentWebpage.embed_width != 0 ? currentWebpage.embed_width : 100;
|
||||
int h = currentWebpage.embed_height != 0 ? currentWebpage.embed_height : 100;
|
||||
int viewWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int viewHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
float minScale = Math.min(viewWidth / (float) w, viewHeight / (float) h);
|
||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) webView.getLayoutParams();
|
||||
layoutParams.width = (int) (w * minScale);
|
||||
layoutParams.height = (int) (h * minScale);
|
||||
layoutParams.topMargin = (viewHeight - layoutParams.height) / 2;
|
||||
layoutParams.leftMargin = (viewWidth - layoutParams.width) / 2;
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
protected void drawBlackBackground(Canvas canvas, int w, int h) {
|
||||
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return progressBar.getVisibility() != View.VISIBLE;
|
||||
}
|
||||
|
||||
public PipVideoView openInPip() {
|
||||
boolean inAppOnly = isYouTube && "inapp".equals(MessagesController.getInstance(currentAccount).youtubePipType);
|
||||
if (!inAppOnly && !checkInlinePermissions()) {
|
||||
return null;
|
||||
}
|
||||
if (progressBar.getVisibility() == View.VISIBLE) {
|
||||
return null;
|
||||
}
|
||||
boolean animated = false;
|
||||
pipVideoView = new PipVideoView(inAppOnly);
|
||||
pipVideoView.show((Activity) getContext(), PhotoViewer.getInstance(), currentWebpage.embed_width != 0 && currentWebpage.embed_height != 0 ? currentWebpage.embed_width / (float) currentWebpage.embed_height : 1.0f, 0, webView);
|
||||
return pipVideoView;
|
||||
}
|
||||
|
||||
public void setPlaybackSpeed(float speed) {
|
||||
playbackSpeed = speed;
|
||||
if (progressBar.getVisibility() != View.VISIBLE) {
|
||||
if (isYouTube) {
|
||||
runJsCode("setPlaybackSpeed(" + speed + ");");
|
||||
}
|
||||
} else {
|
||||
setPlaybackSpeed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("AddJavascriptInterface")
|
||||
public void init(int seekTime, TLRPC.WebPage webPage) {
|
||||
currentWebpage = webPage;
|
||||
String currentYoutubeId = WebPlayerView.getYouTubeVideoId(webPage.embed_url);
|
||||
String originalUrl = webPage.url;
|
||||
requestLayout();
|
||||
|
||||
try {
|
||||
if (currentYoutubeId != null) {
|
||||
progressBarBlackBackground.setVisibility(View.VISIBLE);
|
||||
isYouTube = true;
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
webView.addJavascriptInterface(new YoutubeProxy(), "YoutubeProxy");
|
||||
}
|
||||
int seekToTime = 0;
|
||||
if (originalUrl != null) {
|
||||
try {
|
||||
Uri uri = Uri.parse(originalUrl);
|
||||
String t = seekTime > 0 ? "" + seekTime : null;
|
||||
if (t == null) {
|
||||
t = uri.getQueryParameter("t");
|
||||
if (t == null) {
|
||||
t = uri.getQueryParameter("time_continue");
|
||||
}
|
||||
}
|
||||
if (t != null) {
|
||||
if (t.contains("m")) {
|
||||
String[] arg = t.split("m");
|
||||
seekToTime = Utilities.parseInt(arg[0]) * 60 + Utilities.parseInt(arg[1]);
|
||||
} else {
|
||||
seekToTime = Utilities.parseInt(t);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
}
|
||||
webView.loadDataWithBaseURL("https://messenger.telegram.org/", String.format(Locale.US, youtubeFrame, currentYoutubeId, seekToTime), "text/html", "UTF-8", "https://youtube.com");
|
||||
} else {
|
||||
HashMap<String, String> args = new HashMap<>();
|
||||
args.put("Referer", "messenger.telegram.org");
|
||||
webView.loadUrl(webPage.embed_url, args);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
|
||||
pipItem.setEnabled(false);
|
||||
pipItem.setAlpha(0.5f);
|
||||
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
if (currentYoutubeId != null) {
|
||||
progressBarBlackBackground.setVisibility(View.VISIBLE);
|
||||
}
|
||||
webView.setVisibility(View.VISIBLE);
|
||||
webView.setKeepScreenOn(true);
|
||||
if (currentYoutubeId != null && "disabled".equals(MessagesController.getInstance(currentAccount).youtubePipType)) {
|
||||
pipItem.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkInlinePermissions() {
|
||||
if (Build.VERSION.SDK_INT < 23 || Settings.canDrawOverlays(getContext())) {
|
||||
return true;
|
||||
} else {
|
||||
AlertsCreator.createDrawOverlayPermissionDialog((Activity) getContext(), null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void exitFromPip() {
|
||||
if (webView == null || pipVideoView == null) {
|
||||
return;
|
||||
}
|
||||
if (ApplicationLoader.mainInterfacePaused) {
|
||||
try {
|
||||
getContext().startService(new Intent(ApplicationLoader.applicationContext, BringAppForegroundService.class));
|
||||
} catch (Throwable e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
}
|
||||
ViewGroup parent = (ViewGroup) webView.getParent();
|
||||
if (parent != null) {
|
||||
parent.removeView(webView);
|
||||
}
|
||||
addView(webView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT));
|
||||
pipVideoView.close();
|
||||
pipVideoView = null;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
webView.stopLoading();
|
||||
webView.loadUrl("about:blank");
|
||||
webView.destroy();
|
||||
}
|
||||
}
|
|
@ -278,6 +278,10 @@ public class PipVideoView {
|
|||
return show(activity, null, sheet, controls, aspectRatio, rotation, webview);
|
||||
}
|
||||
|
||||
public TextureView show(Activity activity, PhotoViewer viewer, float aspectRatio, int rotation, WebView webview) {
|
||||
return show(activity, viewer, null, null, aspectRatio, rotation, webview);
|
||||
}
|
||||
|
||||
public TextureView show(Activity activity, PhotoViewer viewer, float aspectRatio, int rotation) {
|
||||
return show(activity, viewer, null, null, aspectRatio, rotation, null);
|
||||
}
|
||||
|
@ -432,7 +436,6 @@ public class PipVideoView {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
return textureView;
|
||||
}
|
||||
|
||||
|
|
|
@ -238,6 +238,7 @@ public class RecyclerAnimationScrollHelper {
|
|||
}
|
||||
}
|
||||
|
||||
recyclerView.setScrollEnabled(true);
|
||||
recyclerView.setVerticalScrollBarEnabled(true);
|
||||
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
|
|
|
@ -1948,7 +1948,7 @@ public class RecyclerListView extends RecyclerView {
|
|||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
if (multiSelectionGesture && e.getAction() != MotionEvent.ACTION_UP && e.getAction() != MotionEvent.ACTION_CANCEL) {
|
||||
if (multiSelectionGesture && e.getAction() != MotionEvent.ACTION_DOWN &&e.getAction() != MotionEvent.ACTION_UP && e.getAction() != MotionEvent.ACTION_CANCEL) {
|
||||
if (lastX == Float.MAX_VALUE && lastY == Float.MAX_VALUE) {
|
||||
lastX = e.getX();
|
||||
lastY = e.getY();
|
||||
|
|
|
@ -30,6 +30,7 @@ public class RoundVideoPlayingDrawable extends Drawable {
|
|||
private int progress2Direction = 1;
|
||||
private int progress3Direction = 1;
|
||||
private View parentView;
|
||||
int alpha = 255;
|
||||
|
||||
public RoundVideoPlayingDrawable(View view) {
|
||||
super();
|
||||
|
@ -92,6 +93,9 @@ public class RoundVideoPlayingDrawable extends Drawable {
|
|||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
paint.setColor(Theme.getColor(Theme.key_chat_serviceText));
|
||||
if (alpha != 255) {
|
||||
paint.setAlpha((int) (alpha * (paint.getAlpha() / 255f)));
|
||||
}
|
||||
int x = getBounds().left;
|
||||
int y = getBounds().top;
|
||||
for (int a = 0; a < 3; a++) {
|
||||
|
@ -106,7 +110,7 @@ public class RoundVideoPlayingDrawable extends Drawable {
|
|||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -428,9 +428,9 @@ public class ScrollSlidingTextTabStrip extends HorizontalScrollView {
|
|||
int currentScrollX = getScrollX();
|
||||
int left = child.getLeft();
|
||||
int width = child.getMeasuredWidth();
|
||||
if (left < currentScrollX) {
|
||||
smoothScrollTo(left, 0);
|
||||
} else if (left + width > currentScrollX + getWidth()) {
|
||||
if (left - AndroidUtilities.dp(50) < currentScrollX) {
|
||||
smoothScrollTo(left - AndroidUtilities.dp(50), 0);
|
||||
} else if (left + width + AndroidUtilities.dp(21) > currentScrollX + getWidth()) {
|
||||
smoothScrollTo(left + width, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -488,7 +488,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter
|
|||
|
||||
@Override
|
||||
public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index, boolean needPreview) {
|
||||
if (messageObject == null || mediaPages[0].selectedType != 0 && mediaPages[0].selectedType != 1 && mediaPages[0].selectedType != 5) {
|
||||
if (messageObject == null || mediaPages[0].selectedType != 0 && mediaPages[0].selectedType != 1 && mediaPages[0].selectedType != 3 && mediaPages[0].selectedType != 5) {
|
||||
return null;
|
||||
}
|
||||
final RecyclerListView listView = mediaPages[0].listView;
|
||||
|
@ -544,6 +544,13 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter
|
|||
imageReceiver = cell.getPhotoImage();
|
||||
cell.getLocationInWindow(coords);
|
||||
}
|
||||
} else if (view instanceof SharedLinkCell) {
|
||||
SharedLinkCell cell = (SharedLinkCell) view;
|
||||
MessageObject message = cell.getMessage();
|
||||
if (message != null && message.getId() == messageObject.getId()) {
|
||||
imageReceiver = cell.getLinkImageView();
|
||||
cell.getLocationInWindow(coords);
|
||||
}
|
||||
}
|
||||
if (imageReceiver != null) {
|
||||
PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject();
|
||||
|
@ -3024,7 +3031,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter
|
|||
ArticleViewer.getInstance().open(message);
|
||||
return;
|
||||
} else if (webPage.embed_url != null && webPage.embed_url.length() != 0) {
|
||||
openWebView(webPage);
|
||||
openWebView(webPage, message);
|
||||
return;
|
||||
} else {
|
||||
link = webPage.url;
|
||||
|
@ -3051,8 +3058,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter
|
|||
}
|
||||
}
|
||||
|
||||
private void openWebView(TLRPC.WebPage webPage) {
|
||||
EmbedBottomSheet.show(profileActivity.getParentActivity(), webPage.site_name, webPage.description, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, false);
|
||||
private void openWebView(TLRPC.WebPage webPage, MessageObject message) {
|
||||
EmbedBottomSheet.show(profileActivity.getParentActivity(), message, provider, webPage.site_name, webPage.description, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, false);
|
||||
}
|
||||
|
||||
private void recycleAdapter(RecyclerView.Adapter adapter) {
|
||||
|
@ -3092,8 +3099,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter
|
|||
|
||||
SharedLinkCell.SharedLinkCellDelegate sharedLinkCellDelegate = new SharedLinkCell.SharedLinkCellDelegate() {
|
||||
@Override
|
||||
public void needOpenWebView(TLRPC.WebPage webPage) {
|
||||
openWebView(webPage);
|
||||
public void needOpenWebView(TLRPC.WebPage webPage, MessageObject message) {
|
||||
openWebView(webPage, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -66,6 +66,11 @@ public class TimerDrawable extends Drawable {
|
|||
if (timeString.length() < 2) {
|
||||
timeString += LocaleController.getString("SecretChatTimerDays", R.string.SecretChatTimerDays);
|
||||
}
|
||||
} else if (time >= 30 * 60 * 60 * 24 && time <= 60 * 60 * 24 * 31) {
|
||||
timeString = "" + value / 60 / 60 / 24 / 30;
|
||||
if (timeString.length() < 2) {
|
||||
timeString += LocaleController.getString("SecretChatTimerMonths", R.string.SecretChatTimerMonths);
|
||||
}
|
||||
} else {
|
||||
timeString = "" + value / 60 / 60 / 24 / 7;
|
||||
if (timeString.length() < 2) {
|
||||
|
@ -74,11 +79,6 @@ public class TimerDrawable extends Drawable {
|
|||
timeString = "c";
|
||||
}
|
||||
}
|
||||
/*
|
||||
<string name="SecretChatTimerDays">d</string>
|
||||
<string name="SecretChatTimerSeconds">s</string>
|
||||
<string name="SecretChatTimerMinutes">m</string>
|
||||
*/
|
||||
|
||||
timeWidth = timePaint.measureText(timeString);
|
||||
try {
|
||||
|
|
|
@ -167,6 +167,7 @@ public class UndoView extends FrameLayout {
|
|||
public final static int ACTION_PAYMENT_SUCCESS = 77;
|
||||
public final static int ACTION_PIN_DIALOGS = 78;
|
||||
public final static int ACTION_UNPIN_DIALOGS = 79;
|
||||
public final static int ACTION_EMAIL_COPIED = 80;
|
||||
|
||||
public final static int ACTION_NEED_RESATRT = 100;
|
||||
|
||||
|
@ -854,7 +855,7 @@ public class UndoView extends FrameLayout {
|
|||
currentAction == ACTION_FWD_MESSAGES || currentAction == ACTION_NOTIFY_ON || currentAction == ACTION_NOTIFY_OFF || currentAction == ACTION_USERNAME_COPIED ||
|
||||
currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED ||
|
||||
currentAction == ACTION_AUTO_DELETE_OFF || currentAction == ACTION_AUTO_DELETE_ON || currentAction == ACTION_GIGAGROUP_CANCEL || currentAction == ACTION_GIGAGROUP_SUCCESS ||
|
||||
currentAction == ACTION_VOIP_INVITE_LINK_SENT || currentAction == ACTION_PIN_DIALOGS || currentAction == ACTION_UNPIN_DIALOGS || currentAction == ACTION_SHARE_BACKGROUND) {
|
||||
currentAction == ACTION_VOIP_INVITE_LINK_SENT || currentAction == ACTION_PIN_DIALOGS || currentAction == ACTION_UNPIN_DIALOGS || currentAction == ACTION_SHARE_BACKGROUND || currentAction == ACTION_EMAIL_COPIED) {
|
||||
undoImageView.setVisibility(GONE);
|
||||
leftImageView.setVisibility(VISIBLE);
|
||||
|
||||
|
@ -877,7 +878,9 @@ public class UndoView extends FrameLayout {
|
|||
int ttl = (Integer) infoObject2;
|
||||
String time;
|
||||
subinfoTextView.setSingleLine(false);
|
||||
if (ttl > 24 * 60 * 60) {
|
||||
if (ttl >= 30 * 24 * 60 * 60) {
|
||||
time = LocaleController.formatPluralString("Months", ttl / (30 * 24 * 60 * 60));
|
||||
} else if (ttl > 24 * 60 * 60) {
|
||||
time = LocaleController.formatPluralString("Days", ttl / (24 * 60 * 60));
|
||||
} else if (ttl >= 60 * 60) {
|
||||
time = LocaleController.formatPluralString("Hours", ttl / (60 * 60));
|
||||
|
@ -927,9 +930,11 @@ public class UndoView extends FrameLayout {
|
|||
leftImageView.setAnimation(R.raw.audio_speed, 36, 36);
|
||||
timeLeft = 3000;
|
||||
infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
} else if (currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED) {
|
||||
} else if (currentAction == ACTION_MESSAGE_COPIED || currentAction == ACTION_USERNAME_COPIED || currentAction == ACTION_HASHTAG_COPIED || currentAction == ACTION_TEXT_COPIED || currentAction == ACTION_LINK_COPIED || currentAction == ACTION_PHONE_COPIED || currentAction == ACTION_EMAIL_COPIED) {
|
||||
int iconRawId = R.raw.copy;
|
||||
if (currentAction == ACTION_PHONE_COPIED) {
|
||||
if (currentAction == ACTION_EMAIL_COPIED) {
|
||||
infoTextView.setText(LocaleController.getString("EmailCopied", R.string.EmailCopied));
|
||||
} else if (currentAction == ACTION_PHONE_COPIED) {
|
||||
infoTextView.setText(LocaleController.getString("PhoneCopied", R.string.PhoneCopied));
|
||||
} else if (currentAction == ACTION_USERNAME_COPIED) {
|
||||
infoTextView.setText(LocaleController.getString("UsernameCopied", R.string.UsernameCopied));
|
||||
|
|
|
@ -17,6 +17,9 @@ public class VideoForwardDrawable extends Drawable {
|
|||
private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Path path1 = new Path();
|
||||
private boolean leftSide;
|
||||
private boolean isRound;
|
||||
private Path clippingPath;
|
||||
private int lastClippingPath;
|
||||
|
||||
private final static int[] playPath = new int[] {10, 7, 26, 16, 10, 25};
|
||||
|
||||
|
@ -46,7 +49,8 @@ public class VideoForwardDrawable extends Drawable {
|
|||
void invalidate();
|
||||
}
|
||||
|
||||
public VideoForwardDrawable() {
|
||||
public VideoForwardDrawable(boolean isRound) {
|
||||
this.isRound = isRound;
|
||||
paint.setColor(0xffffffff);
|
||||
textPaint.setColor(0xffffffff);
|
||||
textPaint.setTextSize(AndroidUtilities.dp(12));
|
||||
|
@ -131,7 +135,21 @@ public class VideoForwardDrawable extends Drawable {
|
|||
}
|
||||
|
||||
canvas.save();
|
||||
canvas.clipRect(rect.left, rect.top, rect.right, rect.bottom);
|
||||
if (isRound) {
|
||||
if (clippingPath == null) {
|
||||
clippingPath = new Path();
|
||||
}
|
||||
int clippingPathHash = rect.left + (rect.top << 8) + (rect.bottom << 16) + (rect.right << 24);
|
||||
if (lastClippingPath != clippingPathHash) {
|
||||
clippingPath.reset();
|
||||
AndroidUtilities.rectTmp.set(rect);
|
||||
clippingPath.addOval(AndroidUtilities.rectTmp, Path.Direction.CCW);
|
||||
lastClippingPath = clippingPathHash;
|
||||
}
|
||||
canvas.clipPath(clippingPath);
|
||||
} else {
|
||||
canvas.clipRect(rect.left, rect.top, rect.right, rect.bottom);
|
||||
}
|
||||
if (!isOneShootAnimation) {
|
||||
paint.setAlpha((int) (80 * enterAnimationProgress));
|
||||
textPaint.setAlpha((int) (255 * enterAnimationProgress));
|
||||
|
|
|
@ -54,8 +54,8 @@ public class ViewPagerFixed extends FrameLayout {
|
|||
|
||||
int currentPosition;
|
||||
int nextPosition;
|
||||
private View viewPages[];
|
||||
private int viewTypes[];
|
||||
private View[] viewPages;
|
||||
private int[] viewTypes;
|
||||
|
||||
protected SparseArray<View> viewsByType = new SparseArray<>();
|
||||
|
||||
|
@ -947,11 +947,6 @@ public class ViewPagerFixed extends FrameLayout {
|
|||
startSmoothScroll(linearSmoothScroller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||
return super.scrollHorizontallyBy(dx, recycler, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(@NonNull RecyclerView.Recycler recycler, @NonNull RecyclerView.State state, @NonNull AccessibilityNodeInfoCompat info) {
|
||||
super.onInitializeAccessibilityNodeInfo(recycler, state, info);
|
||||
|
|
|
@ -2071,7 +2071,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD
|
|||
return inFullscreen;
|
||||
}
|
||||
|
||||
public String getYouTubeVideoId(String url) {
|
||||
public static String getYouTubeVideoId(String url) {
|
||||
Matcher matcher = youtubeIdRegex.matcher(url);
|
||||
String id = null;
|
||||
if (matcher.find()) {
|
||||
|
|
|
@ -1144,6 +1144,7 @@ public class GroupCallRenderersContainer extends FrameLayout {
|
|||
super.onAnimationEnd(animation);
|
||||
swipeToBackAnimator = null;
|
||||
swipeToBackDy = 0;
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
swipeToBackAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||
|
|
|
@ -0,0 +1,585 @@
|
|||
package org.telegram.ui.Components.voip;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.media.projection.MediaProjectionManager;
|
||||
import android.os.Build;
|
||||
import android.os.Parcelable;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.messenger.voip.VideoCapturerDevice;
|
||||
import org.telegram.messenger.voip.VoIPService;
|
||||
import org.telegram.ui.ActionBar.ActionBar;
|
||||
import org.telegram.ui.ActionBar.BackDrawable;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.MotionBackgroundDrawable;
|
||||
import org.telegram.ui.Components.RLottieDrawable;
|
||||
import org.telegram.ui.Components.RLottieImageView;
|
||||
import org.telegram.ui.LaunchActivity;
|
||||
import org.webrtc.RendererCommon;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
@TargetApi(21)
|
||||
public abstract class PrivateVideoPreviewDialog extends FrameLayout implements VoIPService.StateListener {
|
||||
|
||||
private boolean isDismissed;
|
||||
private float outProgress;
|
||||
|
||||
private ViewPager viewPager;
|
||||
private TextView positiveButton;
|
||||
private ActionBar actionBar;
|
||||
private LinearLayout titlesLayout;
|
||||
private RLottieImageView micIconView;
|
||||
private TextView[] titles;
|
||||
private VoIPTextureView textureView;
|
||||
private int currentTexturePage = 1;
|
||||
private int visibleCameraPage = 1;
|
||||
private boolean cameraReady;
|
||||
|
||||
public boolean micEnabled;
|
||||
|
||||
private float pageOffset;
|
||||
private int currentPage;
|
||||
|
||||
private boolean needScreencast;
|
||||
|
||||
public PrivateVideoPreviewDialog(Context context, boolean mic, boolean screencast) {
|
||||
super(context);
|
||||
|
||||
needScreencast = screencast;
|
||||
titles = new TextView[needScreencast ? 3 : 2];
|
||||
|
||||
viewPager = new ViewPager(context);
|
||||
AndroidUtilities.setViewPagerEdgeEffectColor(viewPager, 0x7f000000);
|
||||
viewPager.setAdapter(new Adapter());
|
||||
viewPager.setPageMargin(0);
|
||||
viewPager.setOffscreenPageLimit(1);
|
||||
addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
|
||||
private int scrollState = ViewPager.SCROLL_STATE_IDLE;
|
||||
private int willSetPage;
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
currentPage = position;
|
||||
pageOffset = positionOffset;
|
||||
updateTitlesLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int i) {
|
||||
if (scrollState == ViewPager.SCROLL_STATE_IDLE) {
|
||||
if (i <= (needScreencast ? 1 : 0)) {
|
||||
currentTexturePage = 1;
|
||||
} else {
|
||||
currentTexturePage = 2;
|
||||
}
|
||||
onFinishMoveCameraPage();
|
||||
} else {
|
||||
if (i <= (needScreencast ? 1 : 0)) {
|
||||
willSetPage = 1;
|
||||
} else {
|
||||
willSetPage = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
scrollState = state;
|
||||
if (state == ViewPager.SCROLL_STATE_IDLE) {
|
||||
currentTexturePage = willSetPage;
|
||||
onFinishMoveCameraPage();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
textureView = new VoIPTextureView(context, false, false);
|
||||
textureView.renderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
|
||||
textureView.scaleType = VoIPTextureView.SCALE_TYPE_FIT;
|
||||
textureView.clipToTexture = true;
|
||||
textureView.renderer.setAlpha(0);
|
||||
textureView.renderer.setRotateTextureWitchScreen(true);
|
||||
textureView.renderer.setUseCameraRotation(true);
|
||||
addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
|
||||
actionBar = new ActionBar(context);
|
||||
actionBar.setBackButtonDrawable(new BackDrawable(false));
|
||||
actionBar.setBackgroundColor(Color.TRANSPARENT);
|
||||
actionBar.setItemsColor(Theme.getColor(Theme.key_voipgroup_actionBarItems), false);
|
||||
actionBar.setOccupyStatusBar(true);
|
||||
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
|
||||
@Override
|
||||
public void onItemClick(int id) {
|
||||
if (id == -1) {
|
||||
dismiss(false, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
addView(actionBar);
|
||||
|
||||
positiveButton = new TextView(getContext()) {
|
||||
|
||||
private Paint[] gradientPaint = new Paint[titles.length];
|
||||
{
|
||||
for (int a = 0; a < gradientPaint.length; a++) {
|
||||
gradientPaint[a] = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
for (int a = 0; a < gradientPaint.length; a++) {
|
||||
int color1;
|
||||
int color2;
|
||||
int color3;
|
||||
if (a == 0 && needScreencast) {
|
||||
color1 = 0xff77E55C;
|
||||
color2 = 0xff56C7FE;
|
||||
color3 = 0;
|
||||
} else if (a == 0 || a == 1 && needScreencast) {
|
||||
color1 = 0xff57A4FE;
|
||||
color2 = 0xff766EE9;
|
||||
color3 = 0;
|
||||
} else {
|
||||
color1 = 0xff766EE9;
|
||||
color2 = 0xffF05459;
|
||||
color3 = 0xffE4A756;
|
||||
}
|
||||
Shader gradient;
|
||||
if (color3 != 0) {
|
||||
gradient = new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{color1, color2, color3}, null, Shader.TileMode.CLAMP);
|
||||
} else {
|
||||
gradient = new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{color1, color2}, null, Shader.TileMode.CLAMP);
|
||||
}
|
||||
gradientPaint[a].setShader(gradient);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
|
||||
gradientPaint[currentPage].setAlpha(255);
|
||||
canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), gradientPaint[currentPage]);
|
||||
if (pageOffset > 0 && currentPage + 1 < gradientPaint.length) {
|
||||
gradientPaint[currentPage + 1].setAlpha((int) (255 * pageOffset));
|
||||
canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), gradientPaint[currentPage + 1]);
|
||||
}
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
};
|
||||
positiveButton.setMinWidth(AndroidUtilities.dp(64));
|
||||
positiveButton.setTag(Dialog.BUTTON_POSITIVE);
|
||||
positiveButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||
positiveButton.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText));
|
||||
positiveButton.setGravity(Gravity.CENTER);
|
||||
positiveButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
positiveButton.setText(LocaleController.getString("VoipShareVideo", R.string.VoipShareVideo));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
positiveButton.setForeground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_nameText), (int) (255 * 0.3f))));
|
||||
}
|
||||
positiveButton.setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12));
|
||||
positiveButton.setOnClickListener(view -> {
|
||||
if (isDismissed) {
|
||||
return;
|
||||
}
|
||||
if (currentPage == 0 && needScreencast) {
|
||||
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getContext().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
|
||||
((Activity) getContext()).startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), LaunchActivity.SCREEN_CAPTURE_REQUEST_CODE);
|
||||
} else {
|
||||
dismiss(false, true);
|
||||
}
|
||||
});
|
||||
|
||||
addView(positiveButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 0, 0, 0, 64));
|
||||
|
||||
titlesLayout = new LinearLayout(context);
|
||||
addView(titlesLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 64, Gravity.BOTTOM));
|
||||
|
||||
for (int a = 0; a < titles.length; a++) {
|
||||
titles[a] = new TextView(context);
|
||||
titles[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
|
||||
titles[a].setTextColor(0xffffffff);
|
||||
titles[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
titles[a].setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0);
|
||||
titles[a].setGravity(Gravity.CENTER_VERTICAL);
|
||||
titles[a].setSingleLine(true);
|
||||
titlesLayout.addView(titles[a], LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT));
|
||||
if (a == 0 && needScreencast) {
|
||||
titles[a].setText(LocaleController.getString("VoipPhoneScreen", R.string.VoipPhoneScreen));
|
||||
} else if (a == 0 || a == 1 && needScreencast) {
|
||||
titles[a].setText(LocaleController.getString("VoipFrontCamera", R.string.VoipFrontCamera));
|
||||
} else {
|
||||
titles[a].setText(LocaleController.getString("VoipBackCamera", R.string.VoipBackCamera));
|
||||
}
|
||||
int num = a;
|
||||
titles[a].setOnClickListener(view -> viewPager.setCurrentItem(num, true));
|
||||
}
|
||||
|
||||
setAlpha(0);
|
||||
setTranslationX(AndroidUtilities.dp(32));
|
||||
animate().alpha(1f).translationX(0).setDuration(150).start();
|
||||
|
||||
setWillNotDraw(false);
|
||||
|
||||
VoIPService service = VoIPService.getSharedInstance();
|
||||
if (service != null) {
|
||||
textureView.renderer.setMirror(service.isFrontFaceCamera());
|
||||
textureView.renderer.init(VideoCapturerDevice.getEglBase().getEglBaseContext(), new RendererCommon.RendererEvents() {
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) {
|
||||
|
||||
}
|
||||
});
|
||||
service.setLocalSink(textureView.renderer, false);
|
||||
}
|
||||
viewPager.setCurrentItem(needScreencast ? 1 : 0);
|
||||
|
||||
if (mic) {
|
||||
micIconView = new RLottieImageView(context);
|
||||
micIconView.setPadding(AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(9));
|
||||
micIconView.setBackground(Theme.createCircleDrawable(AndroidUtilities.dp(48), ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.3f))));
|
||||
RLottieDrawable micIcon = new RLottieDrawable(R.raw.voice_mini, "" + R.raw.voice_mini, AndroidUtilities.dp(24), AndroidUtilities.dp(24), true, null);
|
||||
micIconView.setAnimation(micIcon);
|
||||
micIconView.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
micEnabled = true;
|
||||
micIcon.setCurrentFrame(micEnabled ? 69 : 36);
|
||||
micIconView.setOnClickListener(v -> {
|
||||
micEnabled = !micEnabled;
|
||||
if (micEnabled) {
|
||||
micIcon.setCurrentFrame(36);
|
||||
micIcon.setCustomEndFrame(69);
|
||||
} else {
|
||||
micIcon.setCurrentFrame(69);
|
||||
micIcon.setCustomEndFrame(99);
|
||||
}
|
||||
micIcon.start();
|
||||
});
|
||||
addView(micIconView, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.BOTTOM, 24, 0, 0, 136));
|
||||
}
|
||||
}
|
||||
|
||||
public void setBottomPadding(int padding) {
|
||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) positiveButton.getLayoutParams();
|
||||
layoutParams.bottomMargin = AndroidUtilities.dp(64) + padding;
|
||||
|
||||
layoutParams = (FrameLayout.LayoutParams) titlesLayout.getLayoutParams();
|
||||
layoutParams.bottomMargin = padding;
|
||||
}
|
||||
|
||||
private void updateTitlesLayout() {
|
||||
View current = titles[currentPage];
|
||||
View next = currentPage < titles.length - 1 ? titles[currentPage + 1] : null;
|
||||
float cx = getMeasuredWidth() / 2;
|
||||
float currentCx = current.getLeft() + current.getMeasuredWidth() / 2;
|
||||
float tx = getMeasuredWidth() / 2 - currentCx;
|
||||
if (next != null) {
|
||||
float nextCx = next.getLeft() + next.getMeasuredWidth() / 2;
|
||||
tx -= (nextCx - currentCx) * pageOffset;
|
||||
}
|
||||
for (int a = 0; a < titles.length; a++) {
|
||||
float alpha;
|
||||
float scale;
|
||||
if (a < currentPage || a > currentPage + 1) {
|
||||
alpha = 0.7f;
|
||||
scale = 0.9f;
|
||||
} else if (a == currentPage) {
|
||||
alpha = 1.0f - 0.3f * pageOffset;
|
||||
scale = 1.0f - 0.1f * pageOffset;
|
||||
} else {
|
||||
alpha = 0.7f + 0.3f * pageOffset;
|
||||
scale = 0.9f + 0.1f * pageOffset;
|
||||
}
|
||||
titles[a].setAlpha(alpha);
|
||||
titles[a].setScaleX(scale);
|
||||
titles[a].setScaleY(scale);
|
||||
}
|
||||
titlesLayout.setTranslationX(tx);
|
||||
positiveButton.invalidate();
|
||||
if (needScreencast && currentPage == 0 && pageOffset <= 0) {
|
||||
textureView.setVisibility(INVISIBLE);
|
||||
} else {
|
||||
textureView.setVisibility(VISIBLE);
|
||||
if (currentPage + (needScreencast ? 0 : 1) == currentTexturePage) {
|
||||
textureView.setTranslationX(-pageOffset * getMeasuredWidth());
|
||||
} else {
|
||||
textureView.setTranslationX((1.0f - pageOffset) * getMeasuredWidth());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
VoIPService service = VoIPService.getSharedInstance();
|
||||
if (service != null) {
|
||||
service.registerStateListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
VoIPService service = VoIPService.getSharedInstance();
|
||||
if (service != null) {
|
||||
service.unregisterStateListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void onFinishMoveCameraPage() {
|
||||
VoIPService service = VoIPService.getSharedInstance();
|
||||
if (currentTexturePage == visibleCameraPage || service == null) {
|
||||
return;
|
||||
}
|
||||
boolean currentFrontface = service.isFrontFaceCamera();
|
||||
if (currentTexturePage == 1 && !currentFrontface || currentTexturePage == 2 && currentFrontface) {
|
||||
saveLastCameraBitmap();
|
||||
cameraReady = false;
|
||||
VoIPService.getSharedInstance().switchCamera();
|
||||
textureView.setAlpha(0.0f);
|
||||
}
|
||||
visibleCameraPage = currentTexturePage;
|
||||
}
|
||||
|
||||
private void saveLastCameraBitmap() {
|
||||
if (!cameraReady) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Bitmap bitmap = textureView.renderer.getBitmap();
|
||||
if (bitmap != null) {
|
||||
Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), textureView.renderer.getMatrix(), true);
|
||||
bitmap.recycle();
|
||||
bitmap = newBitmap;
|
||||
Bitmap lastBitmap = Bitmap.createScaledBitmap(bitmap, 80, (int) (bitmap.getHeight() / (bitmap.getWidth() / 80.0f)), true);
|
||||
if (lastBitmap != null) {
|
||||
if (lastBitmap != bitmap) {
|
||||
bitmap.recycle();
|
||||
}
|
||||
Utilities.blurBitmap(lastBitmap, 7, 1, lastBitmap.getWidth(), lastBitmap.getHeight(), lastBitmap.getRowBytes());
|
||||
File file = new File(ApplicationLoader.getFilesDirFixed(), "cthumb" + visibleCameraPage + ".jpg");
|
||||
FileOutputStream stream = new FileOutputStream(file);
|
||||
lastBitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream);
|
||||
View view = viewPager.findViewWithTag(visibleCameraPage - (needScreencast ? 0 : 1));
|
||||
if (view instanceof ImageView) {
|
||||
((ImageView) view).setImageBitmap(lastBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraFirstFrameAvailable() {
|
||||
if (!cameraReady) {
|
||||
cameraReady = true;
|
||||
textureView.animate().alpha(1f).setDuration(250);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
updateTitlesLayout();
|
||||
}
|
||||
|
||||
public void dismiss(boolean screencast, boolean apply) {
|
||||
if (isDismissed) {
|
||||
return;
|
||||
}
|
||||
isDismissed = true;
|
||||
saveLastCameraBitmap();
|
||||
onDismiss(screencast, apply);
|
||||
animate().alpha(0f).translationX(AndroidUtilities.dp(32)).setDuration(150).setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
if (getParent() != null) {
|
||||
((ViewGroup) getParent()).removeView(PrivateVideoPreviewDialog.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void onDismiss(boolean screencast, boolean apply) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
boolean isLandscape = MeasureSpec.getSize(widthMeasureSpec) > MeasureSpec.getSize(heightMeasureSpec);
|
||||
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) positiveButton.getLayoutParams();
|
||||
if (isLandscape) {
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = AndroidUtilities.dp(80);
|
||||
} else {
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = AndroidUtilities.dp(16);
|
||||
}
|
||||
if (micIconView != null) {
|
||||
marginLayoutParams = (MarginLayoutParams) micIconView.getLayoutParams();
|
||||
if (isLandscape) {
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = AndroidUtilities.dp(88);
|
||||
} else {
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = AndroidUtilities.dp(24);
|
||||
}
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
measureChildWithMargins(titlesLayout, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64), MeasureSpec.EXACTLY), 0);
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
int color = Theme.getColor(Theme.key_voipgroup_actionBar);
|
||||
color = ColorUtils.setAlphaComponent(color, (int) (255 * (getAlpha() * (1f - outProgress))));
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
super.invalidate();
|
||||
if (getParent() != null) {
|
||||
((View) getParent()).invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (VoIPService.getSharedInstance() != null) {
|
||||
textureView.renderer.setMirror(VoIPService.getSharedInstance().isFrontFaceCamera());
|
||||
}
|
||||
}
|
||||
|
||||
private class Adapter extends PagerAdapter {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return titles.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
View view;
|
||||
if (needScreencast && position == 0) {
|
||||
FrameLayout frameLayout = new FrameLayout(getContext());
|
||||
frameLayout.setBackground(new MotionBackgroundDrawable(0xff212E3A, 0xff2B5B4D, 0xff245863, 0xff274558, true));
|
||||
view = frameLayout;
|
||||
|
||||
ImageView imageView = new ImageView(getContext());
|
||||
imageView.setScaleType(ImageView.ScaleType.CENTER);
|
||||
imageView.setImageResource(R.drawable.screencast_big);
|
||||
frameLayout.addView(imageView, LayoutHelper.createFrame(82, 82, Gravity.CENTER, 0, 0, 0, 60));
|
||||
|
||||
TextView textView = new TextView(getContext());
|
||||
textView.setText(LocaleController.getString("VoipVideoPrivateScreenSharing", R.string.VoipVideoPrivateScreenSharing));
|
||||
textView.setGravity(Gravity.CENTER);
|
||||
textView.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||
textView.setTextColor(0xffffffff);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 21, 28, 21, 0));
|
||||
} else {
|
||||
ImageView imageView = new ImageView(getContext());
|
||||
imageView.setImageResource(R.drawable.icplaceholder);
|
||||
imageView.setTag(position);
|
||||
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
File file = new File(ApplicationLoader.getFilesDirFixed(), "cthumb" + (position == 0 || position == 1 && needScreencast ? 1 : 2) + ".jpg");
|
||||
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
|
||||
} catch (Throwable ignore) {
|
||||
|
||||
}
|
||||
if (bitmap != null) {
|
||||
imageView.setImageBitmap(bitmap);
|
||||
} else {
|
||||
imageView.setImageResource(R.drawable.icplaceholder);
|
||||
}
|
||||
|
||||
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
|
||||
view = imageView;
|
||||
}
|
||||
if (view.getParent() != null) {
|
||||
ViewGroup parent = (ViewGroup) view.getParent();
|
||||
parent.removeView(view);
|
||||
}
|
||||
container.addView(view, 0);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
container.removeView((View) object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryItem(ViewGroup container, int position, Object object) {
|
||||
super.setPrimaryItem(container, position, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return view.equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState(Parcelable arg0, ClassLoader arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable saveState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
if (observer != null) {
|
||||
super.unregisterDataSetObserver(observer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,394 +0,0 @@
|
|||
package org.telegram.ui.Components.voip;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.os.Build;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.voip.VideoCapturerDevice;
|
||||
import org.telegram.messenger.voip.VoIPService;
|
||||
import org.telegram.ui.ActionBar.ActionBar;
|
||||
import org.telegram.ui.ActionBar.BackDrawable;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.RLottieDrawable;
|
||||
import org.telegram.ui.Components.RLottieImageView;
|
||||
import org.telegram.ui.Components.RecyclerListView;
|
||||
import org.telegram.ui.GroupCallActivity;
|
||||
import org.webrtc.RendererCommon;
|
||||
|
||||
public abstract class VideoPreviewDialog extends FrameLayout {
|
||||
|
||||
VoIPTextureView textureView;
|
||||
Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
boolean isDismissed;
|
||||
float outProgress;
|
||||
FrameLayout container;
|
||||
|
||||
View negativeButton;
|
||||
View positiveButton;
|
||||
|
||||
private final LinearLayout buttonsLayout;
|
||||
private final ActionBar actionBar;
|
||||
private final RLottieImageView flipIconView;
|
||||
private final RLottieImageView micIconView;
|
||||
|
||||
int flipIconEndFrame;
|
||||
private final TextView subtitle;
|
||||
|
||||
public boolean micEnabled;
|
||||
|
||||
CellFlickerDrawable drawable = new CellFlickerDrawable();
|
||||
|
||||
public VideoPreviewDialog(@NonNull Context context, RecyclerListView listView, RecyclerListView fullscreenListView) {
|
||||
super(context);
|
||||
backgroundPaint.setColor(Theme.getColor(Theme.key_voipgroup_dialogBackground));
|
||||
|
||||
actionBar = new ActionBar(context);
|
||||
|
||||
actionBar.setBackButtonDrawable(new BackDrawable(false));
|
||||
actionBar.setBackgroundColor(Color.TRANSPARENT);
|
||||
actionBar.setItemsColor(Theme.getColor(Theme.key_voipgroup_actionBarItems), false);
|
||||
actionBar.setTitle(LocaleController.getString("CallVideoPreviewTitle", R.string.CallVideoPreviewTitle));
|
||||
actionBar.setOccupyStatusBar(false);
|
||||
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
|
||||
@Override
|
||||
public void onItemClick(int id) {
|
||||
if (id == -1) {
|
||||
dismiss(false);
|
||||
}
|
||||
super.onItemClick(id);
|
||||
}
|
||||
});
|
||||
|
||||
container = new FrameLayout(context);
|
||||
container.setClipChildren(false);
|
||||
|
||||
addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
|
||||
container.addView(actionBar);
|
||||
|
||||
textureView = new VoIPTextureView(context, false, false);
|
||||
textureView.renderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
||||
textureView.setRoundCorners(AndroidUtilities.dp(8));
|
||||
if (VoIPService.getSharedInstance() != null) {
|
||||
textureView.renderer.setMirror(VoIPService.getSharedInstance().isFrontFaceCamera());
|
||||
}
|
||||
textureView.scaleType = VoIPTextureView.SCALE_TYPE_FIT;
|
||||
textureView.clipToTexture = true;
|
||||
textureView.renderer.setAlpha(0);
|
||||
textureView.renderer.setRotateTextureWitchScreen(true);
|
||||
textureView.renderer.setUseCameraRotation(true);
|
||||
|
||||
subtitle = new TextView(context);
|
||||
subtitle.setTextColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_nameText), (int) (255 * 0.4f)));
|
||||
subtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
subtitle.setText(LocaleController.getString("VideoPreviewDesrciption", R.string.VideoPreviewDesrciption));
|
||||
subtitle.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
container.addView(subtitle, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 24, 0, 24, 108));
|
||||
|
||||
buttonsLayout = new LinearLayout(context);
|
||||
buttonsLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
TextView negative = new TextView(getContext()) {
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
setAlpha(enabled ? 1.0f : 0.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(int color) {
|
||||
super.setTextColor(color);
|
||||
setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(color));
|
||||
}
|
||||
};
|
||||
negative.setMinWidth(AndroidUtilities.dp(64));
|
||||
negative.setTag(Dialog.BUTTON_POSITIVE);
|
||||
negative.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||
negative.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText));
|
||||
negative.setGravity(Gravity.CENTER);
|
||||
negative.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
negative.setText(LocaleController.getString("Cancel", R.string.Cancel));
|
||||
negative.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_voipgroup_listViewBackground), ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_nameText), (int) (255 * 0.3f))));
|
||||
negative.setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12));
|
||||
|
||||
negativeButton = negative;
|
||||
|
||||
TextView positive = new TextView(getContext()) {
|
||||
|
||||
Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
Shader gradient = new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{Theme.getColor(Theme.key_voipgroup_unmuteButton), Theme.getColor(Theme.key_voipgroup_unmuteButton2)}, null, Shader.TileMode.CLAMP);
|
||||
gradientPaint.setShader(gradient);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
|
||||
canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), gradientPaint);
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
};
|
||||
positive.setMinWidth(AndroidUtilities.dp(64));
|
||||
positive.setTag(Dialog.BUTTON_POSITIVE);
|
||||
positive.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||
positive.setTextColor(Theme.getColor(Theme.key_voipgroup_nameText));
|
||||
positive.setGravity(Gravity.CENTER);
|
||||
positive.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
positive.setText(LocaleController.getString("ShareVideo", R.string.ShareVideo));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
positive.setForeground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_nameText), (int) (255 * 0.3f))));
|
||||
}
|
||||
positive.setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12));
|
||||
positiveButton = positive;
|
||||
|
||||
buttonsLayout.addView(negative, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 1f, 0, 4, 0, 4, 0));
|
||||
buttonsLayout.addView(positive, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 1f, 0, 4, 0, 4, 0));
|
||||
|
||||
addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
container.addView(buttonsLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM));
|
||||
if (VoIPService.getSharedInstance() != null) {
|
||||
textureView.renderer.init(VideoCapturerDevice.getEglBase().getEglBaseContext(), new RendererCommon.RendererEvents() {
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
textureView.animate().alpha(1f).setDuration(250);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) {
|
||||
|
||||
}
|
||||
});
|
||||
VoIPService.getSharedInstance().setLocalSink(textureView.renderer, false);
|
||||
}
|
||||
|
||||
negative.setOnClickListener(view -> {
|
||||
dismiss(false);
|
||||
});
|
||||
positive.setOnClickListener(view -> {
|
||||
if (isDismissed) {
|
||||
return;
|
||||
}
|
||||
dismiss(true);
|
||||
});
|
||||
|
||||
setAlpha(0);
|
||||
setTranslationX(AndroidUtilities.dp(32));
|
||||
animate().alpha(1f).translationX(0).setDuration(150).start();
|
||||
|
||||
flipIconView = new RLottieImageView(context);
|
||||
flipIconView.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(10));
|
||||
flipIconView.setBackground(Theme.createCircleDrawable(AndroidUtilities.dp(48), ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.3f))));
|
||||
RLottieDrawable flipIcon = new RLottieDrawable(R.raw.camera_flip, "" + R.raw.camera_flip, AndroidUtilities.dp(24), AndroidUtilities.dp(24), true, null);
|
||||
flipIconView.setAnimation(flipIcon);
|
||||
flipIconView.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
flipIconView.setOnClickListener(v -> {
|
||||
if (VoIPService.getSharedInstance() != null) {
|
||||
VoIPService.getSharedInstance().switchCamera();
|
||||
if (flipIconEndFrame == 18) {
|
||||
flipIcon.setCustomEndFrame(flipIconEndFrame = 39);
|
||||
flipIcon.start();
|
||||
} else {
|
||||
flipIcon.setCurrentFrame(0, false);
|
||||
flipIcon.setCustomEndFrame(flipIconEndFrame = 18);
|
||||
flipIcon.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addView(flipIconView, LayoutHelper.createFrame(48, 48));
|
||||
|
||||
|
||||
micIconView = new RLottieImageView(context);
|
||||
micIconView.setPadding(AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(9));
|
||||
micIconView.setBackground(Theme.createCircleDrawable(AndroidUtilities.dp(48), ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.3f))));
|
||||
RLottieDrawable micIcon = new RLottieDrawable(R.raw.voice_mini, "" + R.raw.voice_mini, AndroidUtilities.dp(24), AndroidUtilities.dp(24), true, null);
|
||||
micIconView.setAnimation(micIcon);
|
||||
micIconView.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
micEnabled = true;
|
||||
micIcon.setCurrentFrame(micEnabled ? 69 : 36);
|
||||
micIconView.setOnClickListener(v -> {
|
||||
micEnabled = !micEnabled;
|
||||
if (micEnabled) {
|
||||
micIcon.setCurrentFrame(36);
|
||||
micIcon.setCustomEndFrame(69);
|
||||
} else {
|
||||
micIcon.setCurrentFrame(69);
|
||||
micIcon.setCustomEndFrame(99);
|
||||
}
|
||||
micIcon.start();
|
||||
});
|
||||
addView(micIconView, LayoutHelper.createFrame(48, 48));
|
||||
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
|
||||
public void dismiss(boolean apply) {
|
||||
if (isDismissed) {
|
||||
return;
|
||||
}
|
||||
isDismissed = true;
|
||||
animate().alpha(0f).translationX(AndroidUtilities.dp(32)).setDuration(150).setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
if (getParent() != null) {
|
||||
((ViewGroup) getParent()).removeView(VideoPreviewDialog.this);
|
||||
}
|
||||
onDismiss(apply);
|
||||
}
|
||||
});
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
float x = textureView.getRight() - AndroidUtilities.dp(48 + 12) - textureView.currentClipHorizontal;
|
||||
float y = textureView.getBottom() - AndroidUtilities.dp(48 + 12) - textureView.currentClipVertical;
|
||||
flipIconView.setTranslationX(x);
|
||||
flipIconView.setTranslationY(y);
|
||||
flipIconView.setScaleX(textureView.getScaleX());
|
||||
flipIconView.setScaleY(textureView.getScaleY());
|
||||
flipIconView.setPivotX(getMeasuredWidth() / 2f - x);
|
||||
flipIconView.setPivotY(getMeasuredHeight() / 2f - y);
|
||||
flipIconView.setAlpha(textureView.renderer.getAlpha() * (1f - outProgress));
|
||||
|
||||
|
||||
x = textureView.getLeft() + AndroidUtilities.dp(12) + textureView.currentClipHorizontal;
|
||||
micIconView.setTranslationX(x);
|
||||
micIconView.setTranslationY(y);
|
||||
micIconView.setScaleX(textureView.getScaleX());
|
||||
micIconView.setScaleY(textureView.getScaleY());
|
||||
micIconView.setPivotX(getMeasuredWidth() / 2f - x);
|
||||
micIconView.setPivotY(getMeasuredHeight() / 2f - y);
|
||||
micIconView.setAlpha(textureView.renderer.getAlpha() * (1f - outProgress));
|
||||
|
||||
canvas.drawColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_actionBar), (int) (255 * (1f - outProgress))));
|
||||
if (isDismissed || textureView.renderer.getAlpha() != 1f) {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
if (!textureView.renderer.isFirstFrameRendered() && textureView.renderer.getAlpha() != 1f) {
|
||||
MarginLayoutParams layoutParams = (MarginLayoutParams) textureView.getLayoutParams();
|
||||
AndroidUtilities.rectTmp.set(layoutParams.leftMargin, layoutParams.topMargin, getMeasuredWidth() - layoutParams.rightMargin, getMeasuredHeight() - layoutParams.bottomMargin);
|
||||
float k = !GroupCallActivity.isLandscapeMode ? 9f / 16f : 16f / 9f;
|
||||
|
||||
if (AndroidUtilities.rectTmp.width() / AndroidUtilities.rectTmp.height() > k) {
|
||||
float padding = (AndroidUtilities.rectTmp.width() - AndroidUtilities.rectTmp.height() * k) / 2f;
|
||||
AndroidUtilities.rectTmp.left += padding;
|
||||
AndroidUtilities.rectTmp.right -= padding;
|
||||
} else {
|
||||
float padding = (AndroidUtilities.rectTmp.height() - AndroidUtilities.rectTmp.width() * k) / 2f;
|
||||
AndroidUtilities.rectTmp.top += padding;
|
||||
AndroidUtilities.rectTmp.bottom -= padding;
|
||||
}
|
||||
|
||||
drawable.setParentWidth(getMeasuredWidth());
|
||||
drawable.draw(canvas, AndroidUtilities.rectTmp, AndroidUtilities.dp(8));
|
||||
invalidate();
|
||||
}
|
||||
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void onDismiss(boolean apply) {
|
||||
|
||||
}
|
||||
|
||||
boolean ignoreLayout = false;
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
boolean isLandscape = MeasureSpec.getSize(widthMeasureSpec) > MeasureSpec.getSize(heightMeasureSpec);
|
||||
ignoreLayout = true;
|
||||
|
||||
if (isLandscape) {
|
||||
actionBar.setTitle(null);
|
||||
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) textureView.getLayoutParams();
|
||||
marginLayoutParams.topMargin = AndroidUtilities.dp(8);
|
||||
marginLayoutParams.bottomMargin = AndroidUtilities.dp(76);
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = AndroidUtilities.dp(48);
|
||||
negativeButton.setVisibility(View.VISIBLE);
|
||||
subtitle.setVisibility(View.GONE);
|
||||
|
||||
marginLayoutParams = (MarginLayoutParams) buttonsLayout.getLayoutParams();
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = AndroidUtilities.dp(80);
|
||||
marginLayoutParams.bottomMargin = AndroidUtilities.dp(16);
|
||||
|
||||
} else {
|
||||
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) textureView.getLayoutParams();
|
||||
actionBar.setTitle(LocaleController.getString("CallVideoPreviewTitle", R.string.CallVideoPreviewTitle));
|
||||
marginLayoutParams.topMargin = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(8);
|
||||
marginLayoutParams.bottomMargin = AndroidUtilities.dp(168);
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = AndroidUtilities.dp(12);
|
||||
negativeButton.setVisibility(View.GONE);
|
||||
subtitle.setVisibility(View.VISIBLE);
|
||||
|
||||
marginLayoutParams = (MarginLayoutParams) buttonsLayout.getLayoutParams();
|
||||
marginLayoutParams.rightMargin = marginLayoutParams.leftMargin = marginLayoutParams.bottomMargin = AndroidUtilities.dp(16);
|
||||
}
|
||||
ignoreLayout = false;
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
if (ignoreLayout) {
|
||||
return;
|
||||
}
|
||||
super.requestLayout();
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
int color = Theme.getColor(Theme.key_voipgroup_actionBar);
|
||||
color = ColorUtils.setAlphaComponent(color, (int) (255 * (getAlpha() * (1f - outProgress))));
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
super.invalidate();
|
||||
if (getParent() != null) {
|
||||
((View) getParent()).invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (VoIPService.getSharedInstance() != null) {
|
||||
textureView.renderer.setMirror(VoIPService.getSharedInstance().isFrontFaceCamera());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ public class VoIPFloatingLayout extends FrameLayout {
|
|||
private boolean floatingMode;
|
||||
private boolean setedFloatingMode;
|
||||
private boolean switchingToFloatingMode;
|
||||
private boolean measuredAsFloatingMode;
|
||||
public boolean measuredAsFloatingMode;
|
||||
|
||||
private float overrideCornerRadius = -1f;
|
||||
private boolean active = true;
|
||||
|
@ -81,9 +81,15 @@ public class VoIPFloatingLayout extends FrameLayout {
|
|||
Drawable outerShadow;
|
||||
|
||||
ValueAnimator switchToFloatingModeAnimator;
|
||||
private ValueAnimator.AnimatorUpdateListener progressUpdateListener = valueAnimator -> {
|
||||
toFloatingModeProgress = (float) valueAnimator.getAnimatedValue();
|
||||
invalidate();
|
||||
private ValueAnimator.AnimatorUpdateListener progressUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
toFloatingModeProgress = (float) valueAnimator.getAnimatedValue();
|
||||
if (delegate != null) {
|
||||
delegate.onChange(toFloatingModeProgress, measuredAsFloatingMode);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
ValueAnimator mutedAnimator;
|
||||
|
@ -94,6 +100,11 @@ public class VoIPFloatingLayout extends FrameLayout {
|
|||
|
||||
OnClickListener tapListener;
|
||||
|
||||
private VoIPFloatingLayoutDelegate delegate;
|
||||
|
||||
public interface VoIPFloatingLayoutDelegate {
|
||||
void onChange(float progress, boolean value);
|
||||
}
|
||||
|
||||
public VoIPFloatingLayout(@NonNull Context context) {
|
||||
super(context);
|
||||
|
@ -139,6 +150,9 @@ public class VoIPFloatingLayout extends FrameLayout {
|
|||
setTranslationY(0);
|
||||
}
|
||||
}
|
||||
if (delegate != null) {
|
||||
delegate.onChange(toFloatingModeProgress, measuredAsFloatingMode);
|
||||
}
|
||||
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
|
||||
|
||||
|
@ -166,6 +180,10 @@ public class VoIPFloatingLayout extends FrameLayout {
|
|||
return true;
|
||||
}
|
||||
|
||||
public void setDelegate(VoIPFloatingLayoutDelegate voIPFloatingLayoutDelegate) {
|
||||
delegate = voIPFloatingLayoutDelegate;
|
||||
}
|
||||
|
||||
long startTime;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -448,6 +448,8 @@ public class VoIPPiPView implements VoIPService.StateListener, NotificationCente
|
|||
callingUserIsVideo = service.getRemoteVideoState() == Instance.VIDEO_STATE_ACTIVE;
|
||||
currentUserIsVideo = service.getVideoState(false) == Instance.VIDEO_STATE_ACTIVE || service.getVideoState(false) == Instance.VIDEO_STATE_PAUSED;
|
||||
currentUserTextureView.renderer.setMirror(service.isFrontFaceCamera());
|
||||
currentUserTextureView.setIsScreencast(service.isScreencast());
|
||||
currentUserTextureView.setScreenshareMiniProgress(1.0f, false);
|
||||
}
|
||||
|
||||
if (!animated) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.graphics.BitmapFactory;
|
|||
import android.graphics.Canvas;
|
||||
import android.graphics.Outline;
|
||||
import android.os.Build;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
import android.view.TextureView;
|
||||
|
@ -18,13 +19,18 @@ import android.view.ViewOutlineProvider;
|
|||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.ui.Components.CubicBezierInterpolator;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.MotionBackgroundDrawable;
|
||||
import org.telegram.ui.GroupCallActivity;
|
||||
import org.webrtc.RendererCommon;
|
||||
import org.webrtc.TextureViewRenderer;
|
||||
|
@ -39,10 +45,15 @@ public class VoIPTextureView extends FrameLayout {
|
|||
|
||||
float roundRadius;
|
||||
|
||||
private boolean screencast;
|
||||
|
||||
public final TextureViewRenderer renderer;
|
||||
public TextureView blurRenderer;
|
||||
public final ImageView imageView;
|
||||
public View backgroundView;
|
||||
private FrameLayout screencastView;
|
||||
private ImageView screencastImage;
|
||||
private TextView screencastText;
|
||||
private Bitmap thumb;
|
||||
|
||||
public Bitmap cameraLastBitmap;
|
||||
|
@ -139,6 +150,25 @@ public class VoIPTextureView extends FrameLayout {
|
|||
blurRenderer.setOpaque(false);
|
||||
}
|
||||
|
||||
screencastView = new FrameLayout(getContext());
|
||||
screencastView.setBackground(new MotionBackgroundDrawable(0xff212E3A, 0xff2B5B4D, 0xff245863, 0xff274558, true));
|
||||
addView(screencastView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
||||
screencastView.setVisibility(GONE);
|
||||
|
||||
screencastImage = new ImageView(getContext());
|
||||
screencastImage.setScaleType(ImageView.ScaleType.CENTER);
|
||||
screencastImage.setImageResource(R.drawable.screencast_big);
|
||||
screencastView.addView(screencastImage, LayoutHelper.createFrame(82, 82, Gravity.CENTER, 0, 0, 0, 60));
|
||||
|
||||
screencastText = new TextView(getContext());
|
||||
screencastText.setText(LocaleController.getString("VoipVideoScreenSharing", R.string.VoipVideoScreenSharing));
|
||||
screencastText.setGravity(Gravity.CENTER);
|
||||
screencastText.setLineSpacing(AndroidUtilities.dp(2), 1.0f);
|
||||
screencastText.setTextColor(0xffffffff);
|
||||
screencastText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
screencastText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
screencastView.addView(screencastText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 21, 28, 21, 0));
|
||||
|
||||
if (applyRoundRadius) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
setOutlineProvider(new ViewOutlineProvider() {
|
||||
|
@ -179,6 +209,40 @@ public class VoIPTextureView extends FrameLayout {
|
|||
}
|
||||
}
|
||||
|
||||
public void setScreenshareMiniProgress(float progress, boolean value) {
|
||||
if (!screencast) {
|
||||
return;
|
||||
}
|
||||
float scale = ((View) getParent()).getScaleX();
|
||||
screencastText.setAlpha(1.0f - progress);
|
||||
float sc;
|
||||
if (!value) {
|
||||
sc = 1.0f / scale - 0.4f / scale * progress;
|
||||
} else {
|
||||
sc = 1.0f - 0.4f * progress;
|
||||
}
|
||||
screencastImage.setScaleX(sc);
|
||||
screencastImage.setScaleY(sc);
|
||||
screencastImage.setTranslationY(AndroidUtilities.dp(60) * progress);
|
||||
}
|
||||
|
||||
public void setIsScreencast(boolean value) {
|
||||
screencast = value;
|
||||
screencastView.setVisibility(screencast ? VISIBLE : GONE);
|
||||
if (screencast) {
|
||||
renderer.setVisibility(GONE);
|
||||
if (blurRenderer != null) {
|
||||
blurRenderer.setVisibility(GONE);
|
||||
}
|
||||
imageView.setVisibility(GONE);
|
||||
} else {
|
||||
renderer.setVisibility(VISIBLE);
|
||||
if (blurRenderer != null) {
|
||||
blurRenderer.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onFirstFrameRendered() {
|
||||
VoIPTextureView.this.invalidate();
|
||||
if (renderer.getAlpha() != 1f) {
|
||||
|
@ -233,6 +297,9 @@ public class VoIPTextureView extends FrameLayout {
|
|||
}
|
||||
|
||||
public void setStub(VoIPTextureView from) {
|
||||
if (screencast) {
|
||||
return;
|
||||
}
|
||||
Bitmap bitmap = from.renderer.getBitmap();
|
||||
if (bitmap == null || bitmap.getPixel(0, 0) == 0) {
|
||||
imageView.setImageDrawable(from.imageView.getDrawable());
|
||||
|
|
|
@ -3247,8 +3247,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
|||
|
||||
fragmentContextView = new FragmentContextView(context, this, false) {
|
||||
@Override
|
||||
protected void playbackSpeedChanged(boolean enabled) {
|
||||
getUndoView().showWithAction(0, enabled ? UndoView.ACTION_PLAYBACK_SPEED_ENABLED : UndoView.ACTION_PLAYBACK_SPEED_DISABLED, null);
|
||||
protected void playbackSpeedChanged(float value) {
|
||||
if (Math.abs(value - 1.0f) > 0.001f || Math.abs(value - 1.8f) > 0.001f) {
|
||||
getUndoView().showWithAction(0, Math.abs(value - 1.0f) > 0.001f ? UndoView.ACTION_PLAYBACK_SPEED_ENABLED : UndoView.ACTION_PLAYBACK_SPEED_DISABLED, value, null, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
fragmentContextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0));
|
||||
|
@ -4248,7 +4250,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
|||
if (searchIsShowed) {
|
||||
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
|
||||
}
|
||||
updateVisibleRows(0);
|
||||
if (viewPages != null) {
|
||||
viewPages[0].dialogsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1041,7 +1041,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente
|
|||
ArticleViewer.getInstance().open(message);
|
||||
return;
|
||||
} else if (webPage.embed_url != null && webPage.embed_url.length() != 0) {
|
||||
openWebView(webPage);
|
||||
openWebView(webPage, message);
|
||||
return;
|
||||
} else {
|
||||
link = webPage.url;
|
||||
|
@ -1066,8 +1066,8 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente
|
|||
private final SharedLinkCell.SharedLinkCellDelegate sharedLinkCellDelegate = new SharedLinkCell.SharedLinkCellDelegate() {
|
||||
|
||||
@Override
|
||||
public void needOpenWebView(TLRPC.WebPage webPage) {
|
||||
openWebView(webPage);
|
||||
public void needOpenWebView(TLRPC.WebPage webPage, MessageObject message) {
|
||||
openWebView(webPage, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1446,8 +1446,8 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente
|
|||
}
|
||||
}
|
||||
|
||||
private void openWebView(TLRPC.WebPage webPage) {
|
||||
EmbedBottomSheet.show(parentActivity, webPage.site_name, webPage.description, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, false);
|
||||
private void openWebView(TLRPC.WebPage webPage, MessageObject message) {
|
||||
EmbedBottomSheet.show(parentActivity, message, provider, webPage.site_name, webPage.description, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, false);
|
||||
}
|
||||
|
||||
int lastAccount;
|
||||
|
|
|
@ -145,7 +145,7 @@ import org.telegram.ui.Components.voip.GroupCallGridCell;
|
|||
import org.telegram.ui.Components.voip.GroupCallMiniTextureView;
|
||||
import org.telegram.ui.Components.voip.GroupCallRenderersContainer;
|
||||
import org.telegram.ui.Components.voip.GroupCallStatusIcon;
|
||||
import org.telegram.ui.Components.voip.VideoPreviewDialog;
|
||||
import org.telegram.ui.Components.voip.PrivateVideoPreviewDialog;
|
||||
import org.telegram.ui.Components.voip.VoIPToggleButton;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -229,7 +229,6 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
private int buttonsVisibility;
|
||||
private TextView speakingMembersSubtitle;
|
||||
|
||||
|
||||
public final ArrayList<ChatObject.VideoParticipant> visibleVideoParticipants = new ArrayList<>();
|
||||
|
||||
float progressToHideUi;
|
||||
|
@ -248,7 +247,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
|
||||
private float scrollOffsetY;
|
||||
|
||||
VideoPreviewDialog previewDialog;
|
||||
PrivateVideoPreviewDialog previewDialog;
|
||||
|
||||
private TLRPC.Peer selfPeer;
|
||||
private TLObject userSwitchObject;
|
||||
|
@ -1291,6 +1290,9 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
AndroidUtilities.updateVisibleRows(listView);
|
||||
}
|
||||
} else if (id == NotificationCenter.groupCallScreencastStateChanged) {
|
||||
if (previewDialog != null) {
|
||||
previewDialog.dismiss(true, true);
|
||||
}
|
||||
updateItems();
|
||||
}
|
||||
}
|
||||
|
@ -1368,7 +1370,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
|
||||
try {
|
||||
UpdateCallback updateCallback = new UpdateCallback(listAdapter);
|
||||
setOldRows(listAdapter.addMemberRow, listAdapter.usersStartRow, listAdapter.usersEndRow, listAdapter.invitedStartRow, listAdapter.invitedEndRow, listAdapter.usersVideoGridStartRow, listAdapter.usersVideoGridEndRow, listAdapter.videoGridDividerRow);
|
||||
setOldRows(listAdapter.addMemberRow, listAdapter.usersStartRow, listAdapter.usersEndRow, listAdapter.invitedStartRow, listAdapter.invitedEndRow, listAdapter.usersVideoGridStartRow, listAdapter.usersVideoGridEndRow, listAdapter.videoGridDividerRow, listAdapter.videoNotAvailableRow);
|
||||
listAdapter.updateRows();
|
||||
DiffUtil.calculateDiff(diffUtilsCallback).dispatchUpdatesTo(updateCallback);
|
||||
} catch (Exception e) {
|
||||
|
@ -3030,7 +3032,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
for (int a = 0, N = getChildCount(); a < N; a++) {
|
||||
View child = getChildAt(a);
|
||||
ViewHolder holder = findContainingViewHolder(child);
|
||||
if (holder == null || holder.getItemViewType() == 3 || holder.getItemViewType() == 4 || holder.getItemViewType() == 5) {
|
||||
if (holder == null || holder.getItemViewType() == 3 || holder.getItemViewType() == 4 || holder.getItemViewType() == 5 || holder.getItemViewType() == 6) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3855,7 +3857,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
canvas.restore();
|
||||
|
||||
if (isLandscapeMode && switchToButtonInt2 == 0) {
|
||||
paint.setAlpha((int) (255));
|
||||
paint.setAlpha(255);
|
||||
float x = scheduleButtonTextView.getX() - getX();
|
||||
float y = scheduleButtonTextView.getY() - getY();
|
||||
rect.set(x, y, x + scheduleButtonTextView.getMeasuredWidth(), y + scheduleButtonTextView.getMeasuredHeight());
|
||||
|
@ -4990,18 +4992,24 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
if (VoIPService.getSharedInstance().getVideoState(false) != Instance.VIDEO_STATE_ACTIVE) {
|
||||
undoView[0].hide(false, 1);
|
||||
if (previewDialog == null) {
|
||||
if (VoIPService.getSharedInstance() != null) {
|
||||
VoIPService.getSharedInstance().createCaptureDevice(false);
|
||||
VoIPService voIPService = VoIPService.getSharedInstance();
|
||||
if (voIPService != null) {
|
||||
voIPService.createCaptureDevice(false);
|
||||
}
|
||||
previewDialog = new VideoPreviewDialog(context, listView, fullscreenUsersListView) {
|
||||
previewDialog = new PrivateVideoPreviewDialog(context, true, VoIPService.getSharedInstance().getVideoState(true) != Instance.VIDEO_STATE_ACTIVE) {
|
||||
@Override
|
||||
public void onDismiss(boolean apply) {
|
||||
public void onDismiss(boolean screencast, boolean apply) {
|
||||
boolean showMicIcon = previewDialog.micEnabled;
|
||||
previewDialog = null;
|
||||
VoIPService service = VoIPService.getSharedInstance();
|
||||
if (apply) {
|
||||
if (service != null) {
|
||||
service.setupCaptureDevice(false, showMicIcon);
|
||||
service.setupCaptureDevice(screencast, showMicIcon);
|
||||
}
|
||||
if (screencast) {
|
||||
if (service != null) {
|
||||
service.setVideoState(false, Instance.VIDEO_STATE_INACTIVE);
|
||||
}
|
||||
}
|
||||
updateState(true, false);
|
||||
call.sortParticipants();
|
||||
|
@ -5009,14 +5017,14 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
buttonsContainer.requestLayout();
|
||||
} else {
|
||||
if (service != null) {
|
||||
VoIPService.getSharedInstance().setVideoState(false, Instance.VIDEO_STATE_INACTIVE);
|
||||
service.setVideoState(false, Instance.VIDEO_STATE_INACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
containerView.addView(previewDialog);
|
||||
if (!VoIPService.getSharedInstance().isFrontFaceCamera()) {
|
||||
VoIPService.getSharedInstance().switchCamera();
|
||||
container.addView(previewDialog);
|
||||
if (voIPService != null && !voIPService.isFrontFaceCamera()) {
|
||||
voIPService.switchCamera();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -5775,6 +5783,8 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
}
|
||||
}
|
||||
|
||||
ObjectAnimator subtitleYAnimator;
|
||||
|
||||
private void updateLayout(boolean animated) {
|
||||
float minY = Integer.MAX_VALUE;
|
||||
int N = listView.getChildCount();
|
||||
|
@ -5811,11 +5821,22 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
.setInterpolator(CubicBezierInterpolator.DEFAULT)
|
||||
.start();
|
||||
|
||||
actionBar.getSubtitleTextView().animate()
|
||||
.translationY(show ? 0.0f : AndroidUtilities.dp(20))
|
||||
.setDuration(300)
|
||||
.setInterpolator(CubicBezierInterpolator.DEFAULT)
|
||||
.start();
|
||||
|
||||
if (subtitleYAnimator != null) {
|
||||
subtitleYAnimator.removeAllListeners();
|
||||
subtitleYAnimator.cancel();
|
||||
}
|
||||
subtitleYAnimator = ObjectAnimator.ofFloat(actionBar.getSubtitleTextView(), View.TRANSLATION_Y, actionBar.getSubtitleTextView().getTranslationY(), show ? 0.0f : AndroidUtilities.dp(20));
|
||||
subtitleYAnimator.setDuration(300);
|
||||
subtitleYAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||
subtitleYAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
subtitleYAnimator = null;
|
||||
actionBar.getSubtitleTextView().setTranslationY(show ? 0.0f : AndroidUtilities.dp(20));
|
||||
}
|
||||
});
|
||||
subtitleYAnimator.start();
|
||||
|
||||
actionBar.getAdditionalSubtitleTextView().animate()
|
||||
.translationY(show ? 0.0f : AndroidUtilities.dp(20))
|
||||
|
@ -7349,7 +7370,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
private int usersVideoGridStartRow;
|
||||
private int usersVideoGridEndRow;
|
||||
private int videoGridDividerRow;
|
||||
private int videoCount;
|
||||
private int videoNotAvailableRow;
|
||||
|
||||
private boolean hasSelfUser;
|
||||
|
||||
|
@ -7380,13 +7401,18 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
rowsCount += visibleVideoParticipants.size();
|
||||
usersVideoGridEndRow = rowsCount;
|
||||
|
||||
videoCount = visibleVideoParticipants.size();
|
||||
int videoCount = visibleVideoParticipants.size();
|
||||
|
||||
if (videoCount > 0) {
|
||||
videoGridDividerRow = rowsCount++;
|
||||
} else {
|
||||
videoGridDividerRow = -1;
|
||||
}
|
||||
if (!visibleVideoParticipants.isEmpty() && ChatObject.canManageCalls(currentChat) && call.call.participants_count > accountInstance.getMessagesController().groipCallVideoMaxParticipants) {
|
||||
videoNotAvailableRow = rowsCount++;
|
||||
} else {
|
||||
videoNotAvailableRow = -1;
|
||||
}
|
||||
usersStartRow = rowsCount;
|
||||
rowsCount += call.visibleParticipants.size();
|
||||
usersEndRow = rowsCount;
|
||||
|
@ -7591,7 +7617,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
int type = holder.getItemViewType();
|
||||
if (type == 1) {
|
||||
return true;
|
||||
} else if (type == 3 || type == 4 || type == 5) {
|
||||
} else if (type == 3 || type == 4 || type == 5 || type == 6) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -7670,6 +7696,15 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
}
|
||||
};
|
||||
break;
|
||||
case 6:
|
||||
TextView textView = new TextView(mContext);
|
||||
textView.setTextColor(0xff7B8389);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
|
||||
textView.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
textView.setPadding(0, 0, 0, AndroidUtilities.dp(10));
|
||||
textView.setText(LocaleController.formatString("VoipVideoNotAvailableAdmin", R.string.VoipVideoNotAvailableAdmin, LocaleController.formatPluralString("Members", accountInstance.getMessagesController().groipCallVideoMaxParticipants)));
|
||||
view = textView;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
view = new View(mContext);
|
||||
|
@ -7684,18 +7719,16 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
public int getItemViewType(int position) {
|
||||
if (position == lastRow) {
|
||||
return 3;
|
||||
}
|
||||
if (position == addMemberRow) {
|
||||
} else if (position == addMemberRow) {
|
||||
return 0;
|
||||
}
|
||||
if (position == videoGridDividerRow) {
|
||||
} else if (position == videoGridDividerRow) {
|
||||
return 5;
|
||||
}
|
||||
if (position >= usersStartRow && position < usersEndRow) {
|
||||
} else if (position >= usersStartRow && position < usersEndRow) {
|
||||
return 1;
|
||||
}
|
||||
if (position >= usersVideoGridStartRow && position < usersVideoGridEndRow) {
|
||||
} else if (position >= usersVideoGridStartRow && position < usersVideoGridEndRow) {
|
||||
return 4;
|
||||
} else if (position == videoNotAvailableRow) {
|
||||
return 6;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
@ -7723,8 +7756,9 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
private int oldUsersVideoStartRow;
|
||||
private int oldUsersVideoEndRow;
|
||||
private int oldVideoDividerRow;
|
||||
private int oldVideoNotAvailableRow;
|
||||
|
||||
public void setOldRows(int addMemberRow, int usersStartRow, int usersEndRow, int invitedStartRow, int invitedEndRow, int usersVideoStartRow, int usersVideoEndRow, int videoDividerRow) {
|
||||
public void setOldRows(int addMemberRow, int usersStartRow, int usersEndRow, int invitedStartRow, int invitedEndRow, int usersVideoStartRow, int usersVideoEndRow, int videoDividerRow, int videoNotAvailableRow) {
|
||||
oldAddMemberRow = addMemberRow;
|
||||
oldUsersStartRow = usersStartRow;
|
||||
oldUsersEndRow = usersEndRow;
|
||||
|
@ -7733,6 +7767,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
oldUsersVideoStartRow = usersVideoStartRow;
|
||||
oldUsersVideoEndRow = usersVideoEndRow;
|
||||
oldVideoDividerRow = videoDividerRow;
|
||||
oldVideoNotAvailableRow = videoNotAvailableRow;
|
||||
}
|
||||
|
||||
private DiffUtil.Callback diffUtilsCallback = new DiffUtil.Callback() {
|
||||
|
@ -7757,6 +7792,14 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (listAdapter.videoNotAvailableRow >= 0) {
|
||||
if (oldItemPosition == oldVideoNotAvailableRow && newItemPosition == listAdapter.videoNotAvailableRow) {
|
||||
return true;
|
||||
} else if (oldItemPosition == oldVideoNotAvailableRow && newItemPosition != listAdapter.videoNotAvailableRow ||
|
||||
oldItemPosition != oldVideoNotAvailableRow && newItemPosition == listAdapter.videoNotAvailableRow) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (listAdapter.videoGridDividerRow >= 0 && listAdapter.videoGridDividerRow == newItemPosition && oldItemPosition == oldVideoDividerRow) {
|
||||
return true;
|
||||
}
|
||||
|
@ -7839,7 +7882,7 @@ public class GroupCallActivity extends BottomSheet implements NotificationCenter
|
|||
@Override
|
||||
public void onBackPressed() {
|
||||
if (previewDialog != null) {
|
||||
previewDialog.dismiss(false);
|
||||
previewDialog.dismiss(false, false);
|
||||
return;
|
||||
}
|
||||
if (avatarsPreviewShowed) {
|
||||
|
|
|
@ -266,12 +266,6 @@ public class IntroActivity extends Activity implements NotificationCenter.Notifi
|
|||
destroyed = true;
|
||||
finish();
|
||||
});
|
||||
if (BuildVars.DEBUG_PRIVATE_VERSION) {
|
||||
startMessagingButton.setOnLongClickListener(v -> {
|
||||
ConnectionsManager.getInstance(currentAccount).switchBackend();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bottomPages = new BottomPagesView(this, viewPager, 6);
|
||||
frameLayout.addView(bottomPages, LayoutHelper.createFrame(66, 5, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 350, 0, 0));
|
||||
|
|
|
@ -1851,17 +1851,8 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
}
|
||||
}
|
||||
}
|
||||
if (messageId != null && segments.contains("video")) {
|
||||
String str = data.getQuery();
|
||||
DateFormat dateFormat = new SimpleDateFormat("mm:ss");
|
||||
Date reference = null;
|
||||
try {
|
||||
reference = dateFormat.parse("00:00");
|
||||
Date date = dateFormat.parse(str);
|
||||
videoTimestamp = (int) ((date.getTime() - reference.getTime()) / 1000L);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (messageId != null) {
|
||||
videoTimestamp = getTimestampFromLink(data);
|
||||
}
|
||||
botUser = data.getQueryParameter("start");
|
||||
botChat = data.getQueryParameter("startgroup");
|
||||
|
@ -2608,6 +2599,36 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
return pushOpened;
|
||||
}
|
||||
|
||||
public static int getTimestampFromLink(Uri data) {
|
||||
List<String> segments = data.getPathSegments();
|
||||
String timestampStr = null;
|
||||
if (segments.contains("video")) {
|
||||
timestampStr = data.getQuery();
|
||||
} else if (data.getQueryParameter("t") != null) {
|
||||
timestampStr = data.getQueryParameter("t");
|
||||
}
|
||||
int videoTimestamp = -1;
|
||||
if (timestampStr != null) {
|
||||
try {
|
||||
videoTimestamp = Integer.parseInt(timestampStr);
|
||||
} catch (Throwable ignore) {
|
||||
|
||||
}
|
||||
if (videoTimestamp == - 1) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("mm:ss");
|
||||
Date reference = null;
|
||||
try {
|
||||
reference = dateFormat.parse("00:00");
|
||||
Date date = dateFormat.parse(timestampStr);
|
||||
videoTimestamp = (int) ((date.getTime() - reference.getTime()) / 1000L);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return videoTimestamp;
|
||||
}
|
||||
|
||||
private void openDialogsToSend(boolean animated) {
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("onlySelect", true);
|
||||
|
@ -4007,7 +4028,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
|||
if (requestCode == SCREEN_CAPTURE_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
VoIPService service = VoIPService.getSharedInstance();
|
||||
if (service != null && service.groupCall != null) {
|
||||
if (service != null) {
|
||||
VideoCapturerDevice.mediaProjectionPermissionResultData = data;
|
||||
service.createCaptureDevice(true);
|
||||
}
|
||||
|
|
|
@ -157,6 +157,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
private boolean checkShowPermissions = true;
|
||||
private boolean newAccount;
|
||||
private boolean syncContacts;
|
||||
private boolean testBackend = false;
|
||||
|
||||
private int scrollHeight;
|
||||
|
||||
|
@ -1686,6 +1687,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
|
||||
private CheckBoxCell syncCell;
|
||||
private CheckBoxCell infoCell;
|
||||
private CheckBoxCell testBackendCheckBox;
|
||||
|
||||
private int countryState = 0;
|
||||
|
||||
|
@ -2010,6 +2012,20 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
}
|
||||
allowFlashCall = simcardAvailable && allowCall && allowCancelCall && allowReadCallLog;
|
||||
|
||||
if (BuildVars.DEBUG_PRIVATE_VERSION) {
|
||||
testBackendCheckBox = new CheckBoxCell(context, 2);
|
||||
testBackendCheckBox.setText("Test Backend", "", testBackend, false);
|
||||
addView(testBackendCheckBox, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
|
||||
testBackendCheckBox.setOnClickListener(v -> {
|
||||
if (getParentActivity() == null) {
|
||||
return;
|
||||
}
|
||||
CheckBoxCell cell = (CheckBoxCell) v;
|
||||
testBackend = !testBackend;
|
||||
cell.setChecked(testBackend, true);
|
||||
});
|
||||
}
|
||||
|
||||
HashMap<String, String> languageMap = new HashMap<>();
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().getAssets().open("countries.txt")));
|
||||
|
@ -2138,6 +2154,11 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
return;
|
||||
}
|
||||
String phone = PhoneFormat.stripExceptNumbers("" + codeField.getText() + phoneField.getText());
|
||||
boolean isTestBakcend = BuildVars.DEBUG_PRIVATE_VERSION && getConnectionsManager().isTestBackend();
|
||||
if (isTestBakcend != testBackend) {
|
||||
getConnectionsManager().switchBackend(false);
|
||||
isTestBakcend = testBackend;
|
||||
}
|
||||
if (getParentActivity() instanceof LaunchActivity) {
|
||||
for (int a : SharedConfig.activeAccounts) {
|
||||
UserConfig userConfig = UserConfig.getInstance(a);
|
||||
|
@ -2145,7 +2166,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
|
|||
continue;
|
||||
}
|
||||
String userPhone = userConfig.getCurrentUser().phone;
|
||||
if (PhoneNumberUtils.compare(phone, userPhone) && ConnectionsManager.native_isTestBackend(currentAccount) == ConnectionsManager.native_isTestBackend(a)) {
|
||||
if (PhoneNumberUtils.compare(phone, userPhone) && ConnectionsManager.getInstance(a).isTestBackend() == isTestBakcend) {
|
||||
final int num = a;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
|
||||
builder.setTitle(LocaleController.getString("NekogramWithEmoji", R.string.NekoX));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user