Update to 7.0.0 (2061)

This commit is contained in:
DrKLO 2020-08-15 03:01:55 +03:00
parent 321b756367
commit 6e495f54b8
22 changed files with 253 additions and 123 deletions

View file

@ -26,6 +26,7 @@ dependencies {
compileOnly 'org.checkerframework:checker-compat-qual:2.5.0' compileOnly 'org.checkerframework:checker-compat-qual:2.5.0'
implementation 'com.google.firebase:firebase-messaging:20.2.4' implementation 'com.google.firebase:firebase-messaging:20.2.4'
implementation 'com.google.firebase:firebase-config:19.2.0' implementation 'com.google.firebase:firebase-config:19.2.0'
implementation 'com.google.firebase:firebase-datatransport:17.0.6'
implementation 'com.google.android.gms:play-services-maps:17.0.0' implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.android.gms:play-services-auth:18.1.0' implementation 'com.google.android.gms:play-services-auth:18.1.0'
implementation 'com.google.android.gms:play-services-vision:16.2.0' implementation 'com.google.android.gms:play-services-vision:16.2.0'
@ -279,7 +280,7 @@ android {
} }
} }
defaultConfig.versionCode = 2060 defaultConfig.versionCode = 2061
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.outputs.all { output -> variant.outputs.all { output ->

View file

@ -13,7 +13,6 @@
int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env); int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env);
int videoOnJNILoad(JavaVM *vm, JNIEnv *env); int videoOnJNILoad(JavaVM *vm, JNIEnv *env);
int imageOnJNILoad(JavaVM *vm, JNIEnv *env); int imageOnJNILoad(JavaVM *vm, JNIEnv *env);
int webrtcOnJNILoad(JavaVM *vm, JNIEnv *env);
int tgvoipOnJNILoad(JavaVM *vm, JNIEnv *env); int tgvoipOnJNILoad(JavaVM *vm, JNIEnv *env);
jint JNI_OnLoad(JavaVM *vm, void *reserved) { jint JNI_OnLoad(JavaVM *vm, void *reserved) {
@ -36,13 +35,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
return -1; return -1;
} }
if (webrtcOnJNILoad(vm, env) != JNI_TRUE) { tgvoipOnJNILoad(vm, env);
return -1;
}
if (tgvoipOnJNILoad(vm, env) != JNI_TRUE) {
return -1;
}
return JNI_VERSION_1_6; return JNI_VERSION_1_6;
} }

View file

@ -5,6 +5,9 @@
#include <VideoCapturerInterface.h> #include <VideoCapturerInterface.h>
#include <platform/android/AndroidInterface.h> #include <platform/android/AndroidInterface.h>
#include <platform/android/AndroidContext.h> #include <platform/android/AndroidContext.h>
#include <rtc_base/ssl_adapter.h>
#include <modules/utility/include/jvm_android.h>
#include <sdk/android/native_api/base/init.h>
#include "pc/video_track.h" #include "pc/video_track.h"
#include "legacy/InstanceImplLegacy.h" #include "legacy/InstanceImplLegacy.h"
@ -214,7 +217,23 @@ jobject asJavaFinalState(JNIEnv *env, const FinalState &finalState) {
extern "C" { extern "C" {
bool webrtcLoaded = false;
void initWebRTC(JNIEnv *env) {
if (webrtcLoaded) {
return;
}
JavaVM* vm;
env->GetJavaVM(&vm);
webrtc::InitAndroid(vm);
webrtc::JVM::Initialize(vm);
rtc::InitializeSSL();
webrtcLoaded = true;
}
JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeNativeInstance(JNIEnv *env, jclass clazz, jstring version, jobject instanceObj, jobject config, jstring persistentStateFilePath, jobjectArray endpoints, jobject proxyClass, jint networkType, jobject encryptionKey, jobject remoteSink, jlong videoCapturer, jfloat aspectRatio) { JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeNativeInstance(JNIEnv *env, jclass clazz, jstring version, jobject instanceObj, jobject config, jstring persistentStateFilePath, jobjectArray endpoints, jobject proxyClass, jint networkType, jobject encryptionKey, jobject remoteSink, jlong videoCapturer, jfloat aspectRatio) {
initWebRTC(env);
JavaObject configObject(env, config); JavaObject configObject(env, config);
JavaObject encryptionKeyObject(env, encryptionKey); JavaObject encryptionKeyObject(env, encryptionKey);
std::string v = tgvoip::jni::JavaStringToStdString(env, version); std::string v = tgvoip::jni::JavaStringToStdString(env, version);
@ -381,6 +400,7 @@ JNIEXPORT jobject JNICALL Java_org_telegram_messenger_voip_NativeInstance_stop(J
} }
JNIEXPORT long JNICALL Java_org_telegram_messenger_voip_NativeInstance_createVideoCapturer(JNIEnv *env, jclass clazz, jobject localSink) { JNIEXPORT long JNICALL Java_org_telegram_messenger_voip_NativeInstance_createVideoCapturer(JNIEnv *env, jclass clazz, jobject localSink) {
initWebRTC(env);
std::unique_ptr<VideoCaptureInterface> capture = tgcalls::VideoCaptureInterface::Create(std::make_shared<AndroidContext>(env)); std::unique_ptr<VideoCaptureInterface> capture = tgcalls::VideoCaptureInterface::Create(std::make_shared<AndroidContext>(env));
capture->setOutput(webrtc::JavaToNativeVideoSink(env, localSink)); capture->setOutput(webrtc::JavaToNativeVideoSink(env, localSink));
capture->setState(VideoState::Active); capture->setState(VideoState::Active);

View file

@ -53,7 +53,7 @@ rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> AndroidInterface::makeVide
} }
bool AndroidInterface::supportsEncoding(const std::string &codecName) { bool AndroidInterface::supportsEncoding(const std::string &codecName) {
if (softwareVideoEncoderFactory == nullptr) { if (hardwareVideoEncoderFactory == nullptr) {
JNIEnv *env = webrtc::AttachCurrentThreadIfNeeded(); JNIEnv *env = webrtc::AttachCurrentThreadIfNeeded();
webrtc::ScopedJavaLocalRef<jclass> factory_class = webrtc::ScopedJavaLocalRef<jclass> factory_class =
webrtc::GetClass(env, "org/webrtc/HardwareVideoEncoderFactory"); webrtc::GetClass(env, "org/webrtc/HardwareVideoEncoderFactory");
@ -85,15 +85,3 @@ std::unique_ptr<PlatformInterface> CreatePlatformInterface() {
} }
} // namespace tgcalls } // namespace tgcalls
extern "C" {
int webrtcOnJNILoad(JavaVM *vm, JNIEnv *env) {
webrtc::InitAndroid(vm);
webrtc::JVM::Initialize(vm);
rtc::InitializeSSL();
return JNI_TRUE;
}
}

View file

@ -19,7 +19,7 @@ public class BuildVars {
public static boolean USE_CLOUD_STRINGS = true; public static boolean USE_CLOUD_STRINGS = true;
public static boolean CHECK_UPDATES = true; public static boolean CHECK_UPDATES = true;
public static boolean TON_WALLET_STANDALONE = false; public static boolean TON_WALLET_STANDALONE = false;
public static int BUILD_VERSION = 2060; public static int BUILD_VERSION = 2061;
public static String BUILD_VERSION_STRING = "7.0.0"; public static String BUILD_VERSION_STRING = "7.0.0";
public static int APP_ID = 4; public static int APP_ID = 4;
public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103";

View file

@ -11742,11 +11742,16 @@ public class MessagesController extends BaseController implements NotificationCe
} }
continue; continue;
} }
boolean notificationsDisabled = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !NotificationManagerCompat.from(ApplicationLoader.applicationContext).areNotificationsEnabled()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !NotificationManagerCompat.from(ApplicationLoader.applicationContext).areNotificationsEnabled()) {
if (BuildVars.LOGS_ENABLED) notificationsDisabled = true;
if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn) {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("Ignoring incoming call because notifications are disabled in system"); FileLog.d("Ignoring incoming call because notifications are disabled in system");
}
continue; continue;
} }
}
TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
if (svc != null || VoIPService.callIShouldHavePutIntoIntent != null || tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) { if (svc != null || VoIPService.callIShouldHavePutIntoIntent != null || tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
if (BuildVars.LOGS_ENABLED) { if (BuildVars.LOGS_ENABLED) {
@ -11773,8 +11778,9 @@ public class MessagesController extends BaseController implements NotificationCe
intent.putExtra("is_outgoing", false); intent.putExtra("is_outgoing", false);
intent.putExtra("user_id", call.participant_id == getUserConfig().getClientUserId() ? call.admin_id : call.participant_id); intent.putExtra("user_id", call.participant_id == getUserConfig().getClientUserId() ? call.admin_id : call.participant_id);
intent.putExtra("account", currentAccount); intent.putExtra("account", currentAccount);
intent.putExtra("notifications_disabled", notificationsDisabled);
try { try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (!notificationsDisabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ApplicationLoader.applicationContext.startForegroundService(intent); ApplicationLoader.applicationContext.startForegroundService(intent);
} else { } else {
ApplicationLoader.applicationContext.startService(intent); ApplicationLoader.applicationContext.startService(intent);

View file

@ -76,7 +76,7 @@ public class SharedConfig {
public static boolean saveToGallery; public static boolean saveToGallery;
public static int mapPreviewType = 2; public static int mapPreviewType = 2;
public static boolean chatBubbles = false; public static boolean chatBubbles = Build.VERSION.SDK_INT >= 30;
public static boolean autoplayGifs = true; public static boolean autoplayGifs = true;
public static boolean autoplayVideo = true; public static boolean autoplayVideo = true;
public static boolean raiseToSpeak = true; public static boolean raiseToSpeak = true;
@ -239,7 +239,7 @@ public class SharedConfig {
preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
saveToGallery = preferences.getBoolean("save_gallery", false); saveToGallery = preferences.getBoolean("save_gallery", false);
autoplayGifs = preferences.getBoolean("autoplay_gif", true); autoplayGifs = preferences.getBoolean("autoplay_gif", true);
chatBubbles = preferences.getBoolean("chatBubbles", false); chatBubbles = preferences.getBoolean("chatBubbles", Build.VERSION.SDK_INT >= 30);
autoplayVideo = preferences.getBoolean("autoplay_video", true); autoplayVideo = preferences.getBoolean("autoplay_video", true);
mapPreviewType = preferences.getInt("mapPreviewType", 2); mapPreviewType = preferences.getInt("mapPreviewType", 2);
raiseToSpeak = preferences.getBoolean("raise_to_speak", true); raiseToSpeak = preferences.getBoolean("raise_to_speak", true);

View file

@ -126,6 +126,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList
protected Notification ongoingCallNotification; protected Notification ongoingCallNotification;
protected NativeInstance tgVoip; protected NativeInstance tgVoip;
protected boolean isVideoAvailable; protected boolean isVideoAvailable;
protected boolean notificationsDisabled;
protected boolean switchingCamera; protected boolean switchingCamera;
protected boolean isFrontFaceCamera = true; protected boolean isFrontFaceCamera = true;
protected String lastError; protected String lastError;
@ -370,10 +371,10 @@ public abstract class VoIPBaseService extends Service implements SensorEventList
.setTitle(LocaleController.getString("VoipOutputDevices", R.string.VoipOutputDevices), true) .setTitle(LocaleController.getString("VoipOutputDevices", R.string.VoipOutputDevices), true)
.setItems(new CharSequence[]{ .setItems(new CharSequence[]{
LocaleController.getString("VoipAudioRoutingSpeaker", R.string.VoipAudioRoutingSpeaker), LocaleController.getString("VoipAudioRoutingSpeaker", R.string.VoipAudioRoutingSpeaker),
LocaleController.getString("VoipAudioRoutingEarpiece", R.string.VoipAudioRoutingEarpiece), isHeadsetPlugged ? LocaleController.getString("VoipAudioRoutingHeadset", R.string.VoipAudioRoutingHeadset) : LocaleController.getString("VoipAudioRoutingEarpiece", R.string.VoipAudioRoutingEarpiece),
currentBluetoothDeviceName != null ? currentBluetoothDeviceName : LocaleController.getString("VoipAudioRoutingBluetooth", R.string.VoipAudioRoutingBluetooth)}, currentBluetoothDeviceName != null ? currentBluetoothDeviceName : LocaleController.getString("VoipAudioRoutingBluetooth", R.string.VoipAudioRoutingBluetooth)},
new int[]{R.drawable.calls_menu_speaker, new int[]{R.drawable.calls_menu_speaker,
R.drawable.calls_menu_phone, isHeadsetPlugged ? R.drawable.calls_menu_headset : R.drawable.calls_menu_phone,
R.drawable.calls_menu_bluetooth}, (dialog, which) -> { R.drawable.calls_menu_bluetooth}, (dialog, which) -> {
if (getSharedInstance() == null) { if (getSharedInstance() == null) {
return; return;
@ -577,19 +578,24 @@ public abstract class VoIPBaseService extends Service implements SensorEventList
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
boolean needRing = am.getRingerMode() != AudioManager.RINGER_MODE_SILENT; boolean needRing = am.getRingerMode() != AudioManager.RINGER_MODE_SILENT;
if (needRing) { if (needRing) {
if (!USE_CONNECTION_SERVICE) {
am.requestAudioFocus(this, AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN);
}
ringtonePlayer = new MediaPlayer(); ringtonePlayer = new MediaPlayer();
ringtonePlayer.setOnPreparedListener(mediaPlayer -> ringtonePlayer.start()); ringtonePlayer.setOnPreparedListener(mediaPlayer -> ringtonePlayer.start());
ringtonePlayer.setLooping(true); ringtonePlayer.setLooping(true);
if (isHeadsetPlugged) {
ringtonePlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
} else {
ringtonePlayer.setAudioStreamType(AudioManager.STREAM_RING); ringtonePlayer.setAudioStreamType(AudioManager.STREAM_RING);
if (!USE_CONNECTION_SERVICE) {
am.requestAudioFocus(this, AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN);
}
}
try { try {
String notificationUri; String notificationUri;
if (prefs.getBoolean("custom_" + chatID, false)) if (prefs.getBoolean("custom_" + chatID, false)) {
notificationUri = prefs.getString("ringtone_path_" + chatID, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE).toString()); notificationUri = prefs.getString("ringtone_path_" + chatID, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE).toString());
else } else {
notificationUri = prefs.getString("CallsRingtonePath", RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE).toString()); notificationUri = prefs.getString("CallsRingtonePath", RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE).toString());
}
ringtonePlayer.setDataSource(this, Uri.parse(notificationUri)); ringtonePlayer.setDataSource(this, Uri.parse(notificationUri));
ringtonePlayer.prepareAsync(); ringtonePlayer.prepareAsync();
} catch (Exception e) { } catch (Exception e) {
@ -1323,6 +1329,10 @@ public abstract class VoIPBaseService extends Service implements SensorEventList
return am.isBluetoothScoOn(); return am.isBluetoothScoOn();
} }
public boolean isHeadsetPlugged() {
return isHeadsetPlugged;
}
public void onMediaStateUpdated(int audioState, int videoState) { public void onMediaStateUpdated(int audioState, int videoState) {
AndroidUtilities.runOnUIThread(() -> { AndroidUtilities.runOnUIThread(() -> {
currentAudioState = audioState; currentAudioState = audioState;

View file

@ -18,6 +18,7 @@ import android.app.PendingIntent;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.audiofx.AcousticEchoCanceler; import android.media.audiofx.AcousticEchoCanceler;
import android.media.audiofx.NoiseSuppressor; import android.media.audiofx.NoiseSuppressor;
import android.net.Uri; import android.net.Uri;
@ -25,7 +26,6 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.NotificationManagerCompat;
import android.os.SystemClock; import android.os.SystemClock;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
@ -162,14 +162,21 @@ public class VoIPService extends VoIPBaseService {
isOutgoing = intent.getBooleanExtra("is_outgoing", false); isOutgoing = intent.getBooleanExtra("is_outgoing", false);
videoCall = intent.getBooleanExtra("video_call", false); videoCall = intent.getBooleanExtra("video_call", false);
isVideoAvailable = intent.getBooleanExtra("can_video_call", false); isVideoAvailable = intent.getBooleanExtra("can_video_call", false);
notificationsDisabled = intent.getBooleanExtra("notifications_disabled", false);
user = MessagesController.getInstance(currentAccount).getUser(userID); user = MessagesController.getInstance(currentAccount).getUser(userID);
localSink = new ProxyVideoSink(); localSink = new ProxyVideoSink();
remoteSink = new ProxyVideoSink(); remoteSink = new ProxyVideoSink();
try {
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
isHeadsetPlugged = am.isWiredHeadsetOn();
} catch (Exception e) {
FileLog.e(e);
}
if (videoCall) { if (videoCall) {
videoCapturer = NativeInstance.createVideoCapturer(localSink); videoCapturer = NativeInstance.createVideoCapturer(localSink);
videoState = Instance.VIDEO_STATE_ACTIVE; videoState = Instance.VIDEO_STATE_ACTIVE;
if (!isBtHeadsetConnected) { if (!isBtHeadsetConnected && !isHeadsetPlugged) {
setAudioOutput(0); setAudioOutput(0);
} }
} }
@ -217,7 +224,7 @@ public class VoIPService extends VoIPBaseService {
} else { } else {
videoState = Instance.VIDEO_STATE_INACTIVE; videoState = Instance.VIDEO_STATE_INACTIVE;
} }
if (videoCall && !isBtHeadsetConnected) { if (videoCall && !isBtHeadsetConnected && !isHeadsetPlugged) {
setAudioOutput(0); setAudioOutput(0);
} }
callIShouldHavePutIntoIntent = null; callIShouldHavePutIntoIntent = null;
@ -496,7 +503,7 @@ public class VoIPService extends VoIPBaseService {
FileLog.d("starting ringing for call " + call.id); FileLog.d("starting ringing for call " + call.id);
} }
dispatchStateChanged(STATE_WAITING_INCOMING); dispatchStateChanged(STATE_WAITING_INCOMING);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (!notificationsDisabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
showIncomingNotification(ContactsController.formatName(user.first_name, user.last_name), null, user, call.video, 0); showIncomingNotification(ContactsController.formatName(user.first_name, user.last_name), null, user, call.video, 0);
if (BuildVars.LOGS_ENABLED) { if (BuildVars.LOGS_ENABLED) {
FileLog.d("Showing incoming call notification"); FileLog.d("Showing incoming call notification");
@ -1226,41 +1233,6 @@ public class VoIPService extends VoIPBaseService {
return isVideoAvailable; return isVideoAvailable;
} }
public void onUIForegroundStateChanged(boolean isForeground) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return;
}
if (currentState == STATE_WAITING_INCOMING) {
if (isForeground) {
stopForeground(true);
} else {
if (!((KeyguardManager) getSystemService(KEYGUARD_SERVICE)).inKeyguardRestrictedInputMode()) {
if (NotificationManagerCompat.from(this).areNotificationsEnabled()) {
showIncomingNotification(ContactsController.formatName(user.first_name, user.last_name), null, user, call.video, 0);
} else {
declineIncomingCall(DISCARD_REASON_LINE_BUSY, null);
}
} else {
AndroidUtilities.runOnUIThread(() -> {
Intent intent = new Intent(VoIPService.this, LaunchActivity.class).setAction("voip");
try {
PendingIntent.getActivity(VoIPService.this, 0, intent, 0).send();
} catch (PendingIntent.CanceledException e) {
if (BuildVars.LOGS_ENABLED) {
FileLog.e("error restarting activity", e);
}
declineIncomingCall(DISCARD_REASON_LINE_BUSY, null);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
showNotification();
}
}, 500);
}
}
}
}
void onMediaButtonEvent(KeyEvent ev) { void onMediaButtonEvent(KeyEvent ev) {
if (ev.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK || ev.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE || ev.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { if (ev.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK || ev.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE || ev.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (ev.getAction() == KeyEvent.ACTION_UP) { if (ev.getAction() == KeyEvent.ACTION_UP) {

View file

@ -956,7 +956,7 @@ public class CropView extends FrameLayout implements CropAreaView.AreaViewListen
RectF sizeRect = new RectF(0, 0, RESULT_SIDE, RESULT_SIDE); RectF sizeRect = new RectF(0, 0, RESULT_SIDE, RESULT_SIDE);
private void updateCropTransform() { private void updateCropTransform() {
if (cropTransform == null) { if (cropTransform == null || state == null) {
return; return;
} }
areaView.getCropRect(cropRect); areaView.getCropRect(cropRect);

View file

@ -14,7 +14,6 @@ import androidx.core.view.ViewCompat;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap;
public abstract class SeekBarAccessibilityDelegate extends View.AccessibilityDelegate { public abstract class SeekBarAccessibilityDelegate extends View.AccessibilityDelegate {

View file

@ -10,6 +10,7 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock; import android.os.SystemClock;
import android.text.Layout; import android.text.Layout;
@ -437,7 +438,7 @@ public class AcceptDeclineView extends View {
@Override @Override
public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
AccessibilityNodeInfo nodeInfo = null; AccessibilityNodeInfo nodeInfo;
if (virtualViewId == HOST_VIEW_ID) { if (virtualViewId == HOST_VIEW_ID) {
nodeInfo = AccessibilityNodeInfo.obtain(hostView); nodeInfo = AccessibilityNodeInfo.obtain(hostView);
nodeInfo.setPackageName(hostView.getContext().getPackageName()); nodeInfo.setPackageName(hostView.getContext().getPackageName());
@ -447,10 +448,14 @@ public class AcceptDeclineView extends View {
} else { } else {
nodeInfo = AccessibilityNodeInfo.obtain(hostView, virtualViewId); nodeInfo = AccessibilityNodeInfo.obtain(hostView, virtualViewId);
nodeInfo.setPackageName(hostView.getContext().getPackageName()); nodeInfo.setPackageName(hostView.getContext().getPackageName());
if (Build.VERSION.SDK_INT >= 21) {
nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
}
nodeInfo.setText(getVirtualViewText(virtualViewId)); nodeInfo.setText(getVirtualViewText(virtualViewId));
nodeInfo.setClassName(Button.class.getName()); nodeInfo.setClassName(Button.class.getName());
if (Build.VERSION.SDK_INT >= 24) {
nodeInfo.setImportantForAccessibility(true); nodeInfo.setImportantForAccessibility(true);
}
nodeInfo.setVisibleToUser(true); nodeInfo.setVisibleToUser(true);
nodeInfo.setClickable(true); nodeInfo.setClickable(true);
nodeInfo.setEnabled(true); nodeInfo.setEnabled(true);

View file

@ -1,6 +1,7 @@
package org.telegram.ui.Components.voip; package org.telegram.ui.Components.voip;
import android.content.Context; import android.content.Context;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@ -18,6 +19,14 @@ public class VoIPButtonsLayout extends FrameLayout {
int childWidth; int childWidth;
int childPadding; int childPadding;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!isEnabled()) {
return false;
}
return super.dispatchTouchEvent(ev);
}
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec);

View file

@ -331,7 +331,7 @@ public class VoIPHelper {
onDismiss.run(); onDismiss.run();
}) })
.create(); .create();
if (BuildVars.DEBUG_VERSION && log.exists()) { if (BuildVars.LOGS_ENABLED && log.exists()) {
alert.setNeutralButton("Send log", (dialog, which) -> { alert.setNeutralButton("Send log", (dialog, which) -> {
Intent intent = new Intent(context, LaunchActivity.class); Intent intent = new Intent(context, LaunchActivity.class);
intent.setAction(Intent.ACTION_SEND); intent.setAction(Intent.ACTION_SEND);

View file

@ -134,7 +134,7 @@ public class VoIPPiPView implements VoIPBaseService.StateListener {
}; };
public static void show(Activity activity, int parentWidth, int parentHeight, int animationType) { public static void show(Activity activity, int parentWidth, int parentHeight, int animationType) {
if (instance != null) { if (instance != null || VideoCameraCapturer.eglBase == null) {
return; return;
} }
WindowManager.LayoutParams windowLayoutParams = createWindowLayoutParams(activity, parentWidth, parentHeight, SCALE_NORMAL); WindowManager.LayoutParams windowLayoutParams = createWindowLayoutParams(activity, parentWidth, parentHeight, SCALE_NORMAL);

View file

@ -131,8 +131,12 @@ public class VoIPWindowView extends FrameLayout {
VoIPFragment.clearInstance(); VoIPFragment.clearInstance();
if (lockOnScreen) { if (lockOnScreen) {
try {
WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
wm.removeView(VoIPWindowView.this); wm.removeView(VoIPWindowView.this);
} catch (Exception e) {
}
} else { } else {
animationIndex = NotificationCenter.getInstance(UserConfig.selectedAccount).setAnimationInProgress(animationIndex, null); animationIndex = NotificationCenter.getInstance(UserConfig.selectedAccount).setAnimationInProgress(animationIndex, null);
animate().translationX(getMeasuredWidth()).setListener(new AnimatorListenerAdapter() { animate().translationX(getMeasuredWidth()).setListener(new AnimatorListenerAdapter() {
@ -141,9 +145,14 @@ public class VoIPWindowView extends FrameLayout {
NotificationCenter.getInstance(UserConfig.selectedAccount).onAnimationFinish(animationIndex); NotificationCenter.getInstance(UserConfig.selectedAccount).onAnimationFinish(animationIndex);
if (getParent() != null) { if (getParent() != null) {
activity.setRequestedOrientation(orientationBefore); activity.setRequestedOrientation(orientationBefore);
WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
setVisibility(View.GONE); setVisibility(View.GONE);
try {
wm.removeView(VoIPWindowView.this); wm.removeView(VoIPWindowView.this);
} catch (Exception e) {
}
} }
} }
}).setDuration(animDuration).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); }).setDuration(animDuration).setInterpolator(CubicBezierInterpolator.DEFAULT).start();

View file

@ -2546,7 +2546,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
@Override @Override
public void notifyDataSetChanged() { public void notifyDataSetChanged() {
viewPage.lastItemsCount = getItemCount(); viewPage.lastItemsCount = getItemCount();
try {
super.notifyDataSetChanged(); super.notifyDataSetChanged();
} catch (Exception e) {
FileLog.e(e);
}
} }
}; };
if (AndroidUtilities.isTablet() && openedDialogId != 0) { if (AndroidUtilities.isTablet() && openedDialogId != 0) {

View file

@ -16,7 +16,6 @@ import android.content.pm.PackageManager;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
@ -50,7 +49,6 @@ import androidx.core.graphics.ColorUtils;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.ContactsController; import org.telegram.messenger.ContactsController;
import org.telegram.messenger.Emoji; import org.telegram.messenger.Emoji;
import org.telegram.messenger.FileLog; import org.telegram.messenger.FileLog;
@ -70,6 +68,7 @@ import org.telegram.messenger.voip.VoIPBaseService;
import org.telegram.messenger.voip.VoIPService; import org.telegram.messenger.voip.VoIPService;
import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.DarkAlertDialog;
import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.BackgroundGradientDrawable;
import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.BackupImageView;
@ -195,7 +194,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
boolean hideUiRunnableWaiting; boolean hideUiRunnableWaiting;
Runnable hideUIRunnable = () -> { Runnable hideUIRunnable = () -> {
hideUiRunnableWaiting = false; hideUiRunnableWaiting = false;
if (canHideUI && uiVisible) { if (canHideUI && uiVisible && !emojiExpanded) {
lastContentTapTime = System.currentTimeMillis(); lastContentTapTime = System.currentTimeMillis();
showUi(false); showUi(false);
previousState = currentState; previousState = currentState;
@ -822,7 +821,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
} }
public void switchToPip() { public void switchToPip() {
if (isFinished || !AndroidUtilities.checkInlinePermissions(activity)) { if (isFinished || !AndroidUtilities.checkInlinePermissions(activity) || instance == null) {
return; return;
} }
isFinished = true; isFinished = true;
@ -1041,11 +1040,13 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
} }
private void expandEmoji(boolean expanded) { private void expandEmoji(boolean expanded) {
if (!emojiLoaded || emojiExpanded == expanded) { if (!emojiLoaded || emojiExpanded == expanded || !uiVisible) {
return; return;
} }
emojiExpanded = expanded; emojiExpanded = expanded;
if (expanded) { if (expanded) {
AndroidUtilities.runOnUIThread(hideUIRunnable);
hideUiRunnableWaiting = false;
float s1 = emojiLayout.getMeasuredWidth(); float s1 = emojiLayout.getMeasuredWidth();
float s2 = windowView.getMeasuredWidth() - AndroidUtilities.dp(128); float s2 = windowView.getMeasuredWidth() - AndroidUtilities.dp(128);
float scale = s2 / s1; float scale = s2 / s1;
@ -1079,6 +1080,11 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
emojiRationalTextView.animate().alpha(0).setListener(new AnimatorListenerAdapter() { emojiRationalTextView.animate().alpha(0).setListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
VoIPService service = VoIPService.getSharedInstance();
if (canHideUI && !hideUiRunnableWaiting && service != null && !service.isMicMute()) {
AndroidUtilities.runOnUIThread(hideUIRunnable, 3000);
hideUiRunnableWaiting = true;
}
emojiRationalTextView.setVisibility(View.GONE); emojiRationalTextView.setVisibility(View.GONE);
} }
}).setDuration(150).start(); }).setDuration(150).start();
@ -1098,9 +1104,6 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
if (isFinished || switchingToPip) { if (isFinished || switchingToPip) {
return; return;
} }
if (currentState == VoIPService.DISCARD_REASON_LINE_BUSY) {
currentState = VoIPService.STATE_BUSY;
}
lockOnScreen = false; lockOnScreen = false;
boolean animated = previousState != -1; boolean animated = previousState != -1;
boolean showAcceptDeclineView = false; boolean showAcceptDeclineView = false;
@ -1174,6 +1177,36 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
currentUserTextureView.saveCameraLastBitmap(); currentUserTextureView.saveCameraLastBitmap();
AndroidUtilities.runOnUIThread(() -> windowView.finish(), 200); AndroidUtilities.runOnUIThread(() -> windowView.finish(), 200);
break; break;
case VoIPBaseService.STATE_FAILED:
statusTextView.setText(LocaleController.getString("VoipFailed", R.string.VoipFailed), false, animated);
final VoIPService voipService = VoIPService.getSharedInstance();
final String lastError = voipService != null ? voipService.getLastError() : Instance.ERROR_UNKNOWN;
if (!TextUtils.equals(lastError, Instance.ERROR_UNKNOWN)) {
if (TextUtils.equals(lastError, Instance.ERROR_INCOMPATIBLE)) {
final String name = ContactsController.formatName(callingUser.first_name, callingUser.last_name);
final String message = LocaleController.formatString("VoipPeerIncompatible", R.string.VoipPeerIncompatible, name);
showErrorDialog(AndroidUtilities.replaceTags(message));
} else if (TextUtils.equals(lastError, Instance.ERROR_PEER_OUTDATED)) {
final String name = ContactsController.formatName(callingUser.first_name, callingUser.last_name);
final String message = LocaleController.formatString("VoipPeerOutdated", R.string.VoipPeerOutdated, name);
showErrorDialog(AndroidUtilities.replaceTags(message));
} else if (TextUtils.equals(lastError, Instance.ERROR_PRIVACY)) {
final String name = ContactsController.formatName(callingUser.first_name, callingUser.last_name);
final String message = LocaleController.formatString("CallNotAvailable", R.string.CallNotAvailable, name);
showErrorDialog(AndroidUtilities.replaceTags(message));
} else if (TextUtils.equals(lastError, Instance.ERROR_AUDIO_IO)) {
showErrorDialog("Error initializing audio hardware");
} else if (TextUtils.equals(lastError, Instance.ERROR_LOCALIZED)) {
windowView.finish();
} else if (TextUtils.equals(lastError, Instance.ERROR_CONNECTION_SERVICE)) {
showErrorDialog(LocaleController.getString("VoipErrorUnknown", R.string.VoipErrorUnknown));
} else {
AndroidUtilities.runOnUIThread(() -> windowView.finish(), 1000);
}
} else {
AndroidUtilities.runOnUIThread(() -> windowView.finish(), 1000);
}
break;
} }
if (callingUserIsVideo) { if (callingUserIsVideo) {
@ -1222,6 +1255,9 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
if (uiVisible && canHideUI && !hideUiRunnableWaiting && service != null && !service.isMicMute()) { if (uiVisible && canHideUI && !hideUiRunnableWaiting && service != null && !service.isMicMute()) {
AndroidUtilities.runOnUIThread(hideUIRunnable, 3000); AndroidUtilities.runOnUIThread(hideUIRunnable, 3000);
hideUiRunnableWaiting = true; hideUiRunnableWaiting = true;
} else if (service != null && service.isMicMute()) {
AndroidUtilities.cancelRunOnUIThread(hideUIRunnable);
hideUiRunnableWaiting = false;
} }
if (!uiVisible) { if (!uiVisible) {
statusLayoutOffset -= AndroidUtilities.dp(50); statusLayoutOffset -= AndroidUtilities.dp(50);
@ -1394,6 +1430,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
uiVisibilityAnimator.start(); uiVisibilityAnimator.start();
AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); AndroidUtilities.cancelRunOnUIThread(hideUIRunnable);
hideUiRunnableWaiting = false; hideUiRunnableWaiting = false;
buttonsLayout.setEnabled(false);
} else if (show && !uiVisible) { } else if (show && !uiVisible) {
tapToVideoTooltip.hide(); tapToVideoTooltip.hide();
speakerPhoneIcon.animate().alpha(1f).translationY(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); speakerPhoneIcon.animate().alpha(1f).translationY(0).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
@ -1407,6 +1444,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
uiVisibilityAnimator.addUpdateListener(statusbarAnimatorListener); uiVisibilityAnimator.addUpdateListener(statusbarAnimatorListener);
uiVisibilityAnimator.setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT); uiVisibilityAnimator.setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT);
uiVisibilityAnimator.start(); uiVisibilityAnimator.start();
buttonsLayout.setEnabled(true);
} }
uiVisible = show; uiVisible = show;
@ -1706,7 +1744,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
view.announceForAccessibility(text); view.announceForAccessibility(text);
} }
serviceInstance.setMicMute(micMute); serviceInstance.setMicMute(micMute);
updateButtons(true); updateViewState();
} }
}); });
} }
@ -1762,10 +1800,14 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
speakerPhoneIcon.setImageResource(R.drawable.calls_bluetooth); speakerPhoneIcon.setImageResource(R.drawable.calls_bluetooth);
} else if (service.isSpeakerphoneOn()) { } else if (service.isSpeakerphoneOn()) {
speakerPhoneIcon.setImageResource(R.drawable.calls_speaker); speakerPhoneIcon.setImageResource(R.drawable.calls_speaker);
} else {
if (service.isHeadsetPlugged()) {
speakerPhoneIcon.setImageResource(R.drawable.calls_menu_headset);
} else { } else {
speakerPhoneIcon.setImageResource(R.drawable.calls_menu_phone); speakerPhoneIcon.setImageResource(R.drawable.calls_menu_phone);
} }
} }
}
private void setSpeakerPhoneAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) { private void setSpeakerPhoneAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) {
if (service.isBluetoothOn()) { if (service.isBluetoothOn()) {
@ -1955,6 +1997,19 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification
deviceIsLocked = ((KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE)).inKeyguardRestrictedInputMode(); deviceIsLocked = ((KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE)).inKeyguardRestrictedInputMode();
} }
private void showErrorDialog(CharSequence message) {
if (activity.isFinishing()) {
return;
}
AlertDialog dlg = new DarkAlertDialog.Builder(activity)
.setTitle(LocaleController.getString("VoipFailed", R.string.VoipFailed))
.setMessage(message)
.setPositiveButton(LocaleController.getString("OK", R.string.OK), null)
.show();
dlg.setCanceledOnTouchOutside(true);
dlg.setOnDismissListener(dialog -> windowView.finish());
}
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
private void requestInlinePermissions() { private void requestInlinePermissions() {
new AlertDialog.Builder(activity).setTitle(LocaleController.getString("AppName", R.string.AppName)) new AlertDialog.Builder(activity).setTitle(LocaleController.getString("AppName", R.string.AppName))

View file

@ -21,6 +21,8 @@ import java.nio.ByteBuffer;
import java.util.concurrent.BlockingDeque; import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.telegram.messenger.FileLog;
import org.webrtc.ThreadUtils.ThreadChecker; import org.webrtc.ThreadUtils.ThreadChecker;
/** /**
@ -543,6 +545,7 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
VideoFrame.I420Buffer frameBuffer = allocateI420Buffer(width, height); VideoFrame.I420Buffer frameBuffer = allocateI420Buffer(width, height);
try { //don't crash
buffer.limit(yEnd); buffer.limit(yEnd);
buffer.position(yPos); buffer.position(yPos);
copyPlane( copyPlane(
@ -571,6 +574,9 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
dataV.position(frameBuffer.getStrideV() * chromaHeight); // Seek to beginning of last row. dataV.position(frameBuffer.getStrideV() * chromaHeight); // Seek to beginning of last row.
dataV.put(buffer); // Copy the last row. dataV.put(buffer); // Copy the last row.
} }
} catch (Throwable e) {
FileLog.e(e);
}
return frameBuffer; return frameBuffer;
} }

View file

@ -39,7 +39,10 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory {
// HW H.264 encoder on below devices has poor bitrate control - actual // HW H.264 encoder on below devices has poor bitrate control - actual
// bitrates deviates a lot from the target value. // bitrates deviates a lot from the target value.
private static final List<String> H264_HW_EXCEPTION_MODELS = private static final List<String> H264_HW_EXCEPTION_MODELS =
Arrays.asList("SAMSUNG-SGH-I337", "Nexus 7", "Nexus 4"); Arrays.asList("SAMSUNG-SGH-I337", "Nexus 7", "Nexus 4", "Pixel 3 XL", "Pixel 3");
private static final List<String> VP8_HW_EXCEPTION_MODELS =
Arrays.asList("Pixel 3 XL", "Pixel 3");
@Nullable private final EglBase14.Context sharedContext; @Nullable private final EglBase14.Context sharedContext;
private final boolean enableIntelVp8Encoder; private final boolean enableIntelVp8Encoder;
@ -241,6 +244,9 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory {
} }
private boolean isHardwareSupportedInCurrentSdkVp8(MediaCodecInfo info) { private boolean isHardwareSupportedInCurrentSdkVp8(MediaCodecInfo info) {
if (VP8_HW_EXCEPTION_MODELS.contains(Build.MODEL)) {
return false;
}
String name = info.getName(); String name = info.getName();
// QCOM Vp8 encoder is supported in KITKAT or later. // QCOM Vp8 encoder is supported in KITKAT or later.
return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)

View file

@ -12,6 +12,11 @@ package org.webrtc;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.os.Handler; import android.os.Handler;
import org.telegram.messenger.FileLog;
import java.nio.ByteBuffer;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
/** /**
@ -109,8 +114,48 @@ public class TextureBufferImpl implements VideoFrame.TextureBuffer {
@Override @Override
public VideoFrame.I420Buffer toI420() { public VideoFrame.I420Buffer toI420() {
try {
return ThreadUtils.invokeAtFrontUninterruptibly( return ThreadUtils.invokeAtFrontUninterruptibly(
toI420Handler, () -> yuvConverter.convert(this)); toI420Handler, () -> yuvConverter.convert(this));
} catch (Throwable e) {
FileLog.e(e);
//don't crash if something fails
final int frameWidth = getWidth();
final int frameHeight = getHeight();
final int stride = ((frameWidth + 7) / 8) * 8;
final int uvHeight = (frameHeight + 1) / 2;
final int totalHeight = frameHeight + uvHeight;
final ByteBuffer i420ByteBuffer = JniCommon.nativeAllocateByteBuffer(stride * totalHeight);
while (i420ByteBuffer.hasRemaining()) {
i420ByteBuffer.put((byte) 0);
}
final int viewportWidth = stride / 4;
final int yPos = 0;
final int uPos = yPos + stride * frameHeight;
final int vPos = uPos + stride / 2;
i420ByteBuffer.position(yPos);
i420ByteBuffer.limit(yPos + stride * frameHeight);
final ByteBuffer dataY = i420ByteBuffer.slice();
i420ByteBuffer.position(uPos);
// The last row does not have padding.
final int uvSize = stride * (uvHeight - 1) + stride / 2;
i420ByteBuffer.limit(uPos + uvSize);
final ByteBuffer dataU = i420ByteBuffer.slice();
i420ByteBuffer.position(vPos);
i420ByteBuffer.limit(vPos + uvSize);
final ByteBuffer dataV = i420ByteBuffer.slice();
return JavaI420Buffer.wrap(frameWidth, frameHeight, dataY, stride, dataU, stride, dataV, stride,
() -> JniCommon.nativeFreeByteBuffer(i420ByteBuffer));
}
} }
@Override @Override

View file

@ -3034,6 +3034,7 @@
<string name="CallViaTelegram">Telegram Call</string> <string name="CallViaTelegram">Telegram Call</string>
<string name="VideoCallViaTelegram">Telegram Video Call</string> <string name="VideoCallViaTelegram">Telegram Video Call</string>
<string name="VoipAudioRoutingEarpiece">Earpiece</string> <string name="VoipAudioRoutingEarpiece">Earpiece</string>
<string name="VoipAudioRoutingHeadset">Headset</string>
<string name="VoipAudioRoutingSpeaker">Speaker</string> <string name="VoipAudioRoutingSpeaker">Speaker</string>
<string name="VoipAudioRoutingBluetooth">Bluetooth</string> <string name="VoipAudioRoutingBluetooth">Bluetooth</string>
<string name="VoipOutputDevices">Output Devices</string> <string name="VoipOutputDevices">Output Devices</string>
@ -3078,6 +3079,7 @@
<string name="AcceptCall">Accept</string> <string name="AcceptCall">Accept</string>
<string name="DeclineCall">Decline</string> <string name="DeclineCall">Decline</string>
<string name="RetryCall">Retry</string> <string name="RetryCall">Retry</string>
<string name="VoipVideoUnavailable">Video</string>
<!--contacts shortcuts--> <!--contacts shortcuts-->
<string name="ContactShortcutMessage">Message %1$s</string> <string name="ContactShortcutMessage">Message %1$s</string>
<string name="ContactShortcutVoiceCall">Voice call %1$s</string> <string name="ContactShortcutVoiceCall">Voice call %1$s</string>