diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 9d1a85839..a6f389388 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -26,6 +26,7 @@ dependencies { compileOnly 'org.checkerframework:checker-compat-qual:2.5.0' implementation 'com.google.firebase:firebase-messaging:20.2.4' 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-auth:18.1.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 -> variant.outputs.all { output -> diff --git a/TMessagesProj/jni/jni.c b/TMessagesProj/jni/jni.c index 9e040ae1f..1c34b3e9c 100644 --- a/TMessagesProj/jni/jni.c +++ b/TMessagesProj/jni/jni.c @@ -13,7 +13,6 @@ int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env); int videoOnJNILoad(JavaVM *vm, JNIEnv *env); int imageOnJNILoad(JavaVM *vm, JNIEnv *env); -int webrtcOnJNILoad(JavaVM *vm, JNIEnv *env); int tgvoipOnJNILoad(JavaVM *vm, JNIEnv *env); jint JNI_OnLoad(JavaVM *vm, void *reserved) { @@ -36,13 +35,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { return -1; } - if (webrtcOnJNILoad(vm, env) != JNI_TRUE) { - return -1; - } - - if (tgvoipOnJNILoad(vm, env) != JNI_TRUE) { - return -1; - } + tgvoipOnJNILoad(vm, env); return JNI_VERSION_1_6; } diff --git a/TMessagesProj/jni/libtgvoip/client/android/org_telegram_messenger_voip_Instance.cpp b/TMessagesProj/jni/libtgvoip/client/android/org_telegram_messenger_voip_Instance.cpp index fb7664506..54a65a4d8 100644 --- a/TMessagesProj/jni/libtgvoip/client/android/org_telegram_messenger_voip_Instance.cpp +++ b/TMessagesProj/jni/libtgvoip/client/android/org_telegram_messenger_voip_Instance.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "pc/video_track.h" #include "legacy/InstanceImplLegacy.h" @@ -214,7 +217,23 @@ jobject asJavaFinalState(JNIEnv *env, const FinalState &finalState) { 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) { + initWebRTC(env); + JavaObject configObject(env, config); JavaObject encryptionKeyObject(env, encryptionKey); 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) { + initWebRTC(env); std::unique_ptr capture = tgcalls::VideoCaptureInterface::Create(std::make_shared(env)); capture->setOutput(webrtc::JavaToNativeVideoSink(env, localSink)); capture->setState(VideoState::Active); diff --git a/TMessagesProj/jni/tgcalls/platform/android/AndroidInterface.cpp b/TMessagesProj/jni/tgcalls/platform/android/AndroidInterface.cpp index 24cb938b1..a8e5c47b3 100644 --- a/TMessagesProj/jni/tgcalls/platform/android/AndroidInterface.cpp +++ b/TMessagesProj/jni/tgcalls/platform/android/AndroidInterface.cpp @@ -53,7 +53,7 @@ rtc::scoped_refptr AndroidInterface::makeVide } bool AndroidInterface::supportsEncoding(const std::string &codecName) { - if (softwareVideoEncoderFactory == nullptr) { + if (hardwareVideoEncoderFactory == nullptr) { JNIEnv *env = webrtc::AttachCurrentThreadIfNeeded(); webrtc::ScopedJavaLocalRef factory_class = webrtc::GetClass(env, "org/webrtc/HardwareVideoEncoderFactory"); @@ -85,15 +85,3 @@ std::unique_ptr CreatePlatformInterface() { } } // namespace tgcalls - -extern "C" { - -int webrtcOnJNILoad(JavaVM *vm, JNIEnv *env) { - webrtc::InitAndroid(vm); - webrtc::JVM::Initialize(vm); - rtc::InitializeSSL(); - - return JNI_TRUE; -} - -} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 216980f85..8c25cd0d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -19,7 +19,7 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; 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 int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 3144cb909..93d2402fb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -11742,10 +11742,15 @@ public class MessagesController extends BaseController implements NotificationCe } continue; } + boolean notificationsDisabled = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !NotificationManagerCompat.from(ApplicationLoader.applicationContext).areNotificationsEnabled()) { - if (BuildVars.LOGS_ENABLED) - FileLog.d("Ignoring incoming call because notifications are disabled in system"); - continue; + notificationsDisabled = true; + if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("Ignoring incoming call because notifications are disabled in system"); + } + continue; + } } TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); if (svc != null || VoIPService.callIShouldHavePutIntoIntent != null || tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) { @@ -11773,8 +11778,9 @@ public class MessagesController extends BaseController implements NotificationCe intent.putExtra("is_outgoing", false); intent.putExtra("user_id", call.participant_id == getUserConfig().getClientUserId() ? call.admin_id : call.participant_id); intent.putExtra("account", currentAccount); + intent.putExtra("notifications_disabled", notificationsDisabled); try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!notificationsDisabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ApplicationLoader.applicationContext.startForegroundService(intent); } else { ApplicationLoader.applicationContext.startService(intent); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 2df42902e..0f3a20278 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -76,7 +76,7 @@ public class SharedConfig { public static boolean saveToGallery; 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 autoplayVideo = true; public static boolean raiseToSpeak = true; @@ -239,7 +239,7 @@ public class SharedConfig { preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); saveToGallery = preferences.getBoolean("save_gallery", false); 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); mapPreviewType = preferences.getInt("mapPreviewType", 2); raiseToSpeak = preferences.getBoolean("raise_to_speak", true); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java index d7d00c3f9..5af7e96d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java @@ -126,6 +126,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList protected Notification ongoingCallNotification; protected NativeInstance tgVoip; protected boolean isVideoAvailable; + protected boolean notificationsDisabled; protected boolean switchingCamera; protected boolean isFrontFaceCamera = true; protected String lastError; @@ -370,10 +371,10 @@ public abstract class VoIPBaseService extends Service implements SensorEventList .setTitle(LocaleController.getString("VoipOutputDevices", R.string.VoipOutputDevices), true) .setItems(new CharSequence[]{ 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)}, 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) -> { if (getSharedInstance() == null) { return; @@ -577,19 +578,24 @@ public abstract class VoIPBaseService extends Service implements SensorEventList AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); boolean needRing = am.getRingerMode() != AudioManager.RINGER_MODE_SILENT; if (needRing) { - if (!USE_CONNECTION_SERVICE) { - am.requestAudioFocus(this, AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN); - } ringtonePlayer = new MediaPlayer(); ringtonePlayer.setOnPreparedListener(mediaPlayer -> ringtonePlayer.start()); ringtonePlayer.setLooping(true); - ringtonePlayer.setAudioStreamType(AudioManager.STREAM_RING); + if (isHeadsetPlugged) { + ringtonePlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL); + } else { + ringtonePlayer.setAudioStreamType(AudioManager.STREAM_RING); + if (!USE_CONNECTION_SERVICE) { + am.requestAudioFocus(this, AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN); + } + } try { 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()); - else + } else { notificationUri = prefs.getString("CallsRingtonePath", RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE).toString()); + } ringtonePlayer.setDataSource(this, Uri.parse(notificationUri)); ringtonePlayer.prepareAsync(); } catch (Exception e) { @@ -1323,6 +1329,10 @@ public abstract class VoIPBaseService extends Service implements SensorEventList return am.isBluetoothScoOn(); } + public boolean isHeadsetPlugged() { + return isHeadsetPlugged; + } + public void onMediaStateUpdated(int audioState, int videoState) { AndroidUtilities.runOnUIThread(() -> { currentAudioState = audioState; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java index a5412748a..68ee9adbb 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -18,6 +18,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.media.AudioManager; import android.media.audiofx.AcousticEchoCanceler; import android.media.audiofx.NoiseSuppressor; import android.net.Uri; @@ -25,7 +26,6 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import androidx.annotation.Nullable; -import androidx.core.app.NotificationManagerCompat; import android.os.SystemClock; import android.telecom.TelecomManager; @@ -162,14 +162,21 @@ public class VoIPService extends VoIPBaseService { isOutgoing = intent.getBooleanExtra("is_outgoing", false); videoCall = intent.getBooleanExtra("video_call", false); isVideoAvailable = intent.getBooleanExtra("can_video_call", false); + notificationsDisabled = intent.getBooleanExtra("notifications_disabled", false); user = MessagesController.getInstance(currentAccount).getUser(userID); localSink = new ProxyVideoSink(); remoteSink = new ProxyVideoSink(); + try { + AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); + isHeadsetPlugged = am.isWiredHeadsetOn(); + } catch (Exception e) { + FileLog.e(e); + } if (videoCall) { videoCapturer = NativeInstance.createVideoCapturer(localSink); videoState = Instance.VIDEO_STATE_ACTIVE; - if (!isBtHeadsetConnected) { + if (!isBtHeadsetConnected && !isHeadsetPlugged) { setAudioOutput(0); } } @@ -217,7 +224,7 @@ public class VoIPService extends VoIPBaseService { } else { videoState = Instance.VIDEO_STATE_INACTIVE; } - if (videoCall && !isBtHeadsetConnected) { + if (videoCall && !isBtHeadsetConnected && !isHeadsetPlugged) { setAudioOutput(0); } callIShouldHavePutIntoIntent = null; @@ -496,7 +503,7 @@ public class VoIPService extends VoIPBaseService { FileLog.d("starting ringing for call " + call.id); } 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); if (BuildVars.LOGS_ENABLED) { FileLog.d("Showing incoming call notification"); @@ -1226,41 +1233,6 @@ public class VoIPService extends VoIPBaseService { 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) { 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) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java index 7f900f293..2efe5aaa3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Crop/CropView.java @@ -956,7 +956,7 @@ public class CropView extends FrameLayout implements CropAreaView.AreaViewListen RectF sizeRect = new RectF(0, 0, RESULT_SIDE, RESULT_SIDE); private void updateCropTransform() { - if (cropTransform == null) { + if (cropTransform == null || state == null) { return; } areaView.getCropRect(cropRect); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarAccessibilityDelegate.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarAccessibilityDelegate.java index 230550b82..dfddaeba1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarAccessibilityDelegate.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarAccessibilityDelegate.java @@ -14,7 +14,6 @@ import androidx.core.view.ViewCompat; import java.util.HashMap; import java.util.Map; -import java.util.WeakHashMap; public abstract class SeekBarAccessibilityDelegate extends View.AccessibilityDelegate { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java index 9a5b4127d..dc7ae89f2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/AcceptDeclineView.java @@ -10,6 +10,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.text.Layout; @@ -437,7 +438,7 @@ public class AcceptDeclineView extends View { @Override public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { - AccessibilityNodeInfo nodeInfo = null; + AccessibilityNodeInfo nodeInfo; if (virtualViewId == HOST_VIEW_ID) { nodeInfo = AccessibilityNodeInfo.obtain(hostView); nodeInfo.setPackageName(hostView.getContext().getPackageName()); @@ -447,10 +448,14 @@ public class AcceptDeclineView extends View { } else { nodeInfo = AccessibilityNodeInfo.obtain(hostView, virtualViewId); nodeInfo.setPackageName(hostView.getContext().getPackageName()); - nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); + if (Build.VERSION.SDK_INT >= 21) { + nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); + } nodeInfo.setText(getVirtualViewText(virtualViewId)); nodeInfo.setClassName(Button.class.getName()); - nodeInfo.setImportantForAccessibility(true); + if (Build.VERSION.SDK_INT >= 24) { + nodeInfo.setImportantForAccessibility(true); + } nodeInfo.setVisibleToUser(true); nodeInfo.setClickable(true); nodeInfo.setEnabled(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPButtonsLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPButtonsLayout.java index 8526b6986..0b7da3a6c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPButtonsLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPButtonsLayout.java @@ -1,6 +1,7 @@ package org.telegram.ui.Components.voip; import android.content.Context; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; @@ -18,6 +19,14 @@ public class VoIPButtonsLayout extends FrameLayout { int childWidth; int childPadding; + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (!isEnabled()) { + return false; + } + return super.dispatchTouchEvent(ev); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java index 6c8bbd00a..6fd72cdae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPHelper.java @@ -331,7 +331,7 @@ public class VoIPHelper { onDismiss.run(); }) .create(); - if (BuildVars.DEBUG_VERSION && log.exists()) { + if (BuildVars.LOGS_ENABLED && log.exists()) { alert.setNeutralButton("Send log", (dialog, which) -> { Intent intent = new Intent(context, LaunchActivity.class); intent.setAction(Intent.ACTION_SEND); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPPiPView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPPiPView.java index 396b34129..4c8437302 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPPiPView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPPiPView.java @@ -134,7 +134,7 @@ public class VoIPPiPView implements VoIPBaseService.StateListener { }; public static void show(Activity activity, int parentWidth, int parentHeight, int animationType) { - if (instance != null) { + if (instance != null || VideoCameraCapturer.eglBase == null) { return; } WindowManager.LayoutParams windowLayoutParams = createWindowLayoutParams(activity, parentWidth, parentHeight, SCALE_NORMAL); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java index 5709d7d96..cc683e509 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java @@ -131,8 +131,12 @@ public class VoIPWindowView extends FrameLayout { VoIPFragment.clearInstance(); if (lockOnScreen) { - WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); - wm.removeView(VoIPWindowView.this); + try { + WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(VoIPWindowView.this); + } catch (Exception e) { + + } } else { animationIndex = NotificationCenter.getInstance(UserConfig.selectedAccount).setAnimationInProgress(animationIndex, null); animate().translationX(getMeasuredWidth()).setListener(new AnimatorListenerAdapter() { @@ -141,9 +145,14 @@ public class VoIPWindowView extends FrameLayout { NotificationCenter.getInstance(UserConfig.selectedAccount).onAnimationFinish(animationIndex); if (getParent() != null) { activity.setRequestedOrientation(orientationBefore); + WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); setVisibility(View.GONE); - wm.removeView(VoIPWindowView.this); + try { + wm.removeView(VoIPWindowView.this); + } catch (Exception e) { + + } } } }).setDuration(animDuration).setInterpolator(CubicBezierInterpolator.DEFAULT).start(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index da1de16ca..72eb2b5c2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -2546,7 +2546,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. @Override public void notifyDataSetChanged() { viewPage.lastItemsCount = getItemCount(); - super.notifyDataSetChanged(); + try { + super.notifyDataSetChanged(); + } catch (Exception e) { + FileLog.e(e); + } } }; if (AndroidUtilities.isTablet() && openedDialogId != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java index 694210186..1e37cbd9a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java @@ -16,7 +16,6 @@ import android.content.pm.PackageManager; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.os.Build; @@ -50,7 +49,6 @@ import androidx.core.graphics.ColorUtils; import androidx.core.view.ViewCompat; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; @@ -70,6 +68,7 @@ import org.telegram.messenger.voip.VoIPBaseService; import org.telegram.messenger.voip.VoIPService; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.DarkAlertDialog; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.BackupImageView; @@ -195,7 +194,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification boolean hideUiRunnableWaiting; Runnable hideUIRunnable = () -> { hideUiRunnableWaiting = false; - if (canHideUI && uiVisible) { + if (canHideUI && uiVisible && !emojiExpanded) { lastContentTapTime = System.currentTimeMillis(); showUi(false); previousState = currentState; @@ -822,7 +821,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification } public void switchToPip() { - if (isFinished || !AndroidUtilities.checkInlinePermissions(activity)) { + if (isFinished || !AndroidUtilities.checkInlinePermissions(activity) || instance == null) { return; } isFinished = true; @@ -1041,11 +1040,13 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification } private void expandEmoji(boolean expanded) { - if (!emojiLoaded || emojiExpanded == expanded) { + if (!emojiLoaded || emojiExpanded == expanded || !uiVisible) { return; } emojiExpanded = expanded; if (expanded) { + AndroidUtilities.runOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; float s1 = emojiLayout.getMeasuredWidth(); float s2 = windowView.getMeasuredWidth() - AndroidUtilities.dp(128); float scale = s2 / s1; @@ -1079,6 +1080,11 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification emojiRationalTextView.animate().alpha(0).setListener(new AnimatorListenerAdapter() { @Override 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); } }).setDuration(150).start(); @@ -1098,9 +1104,6 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification if (isFinished || switchingToPip) { return; } - if (currentState == VoIPService.DISCARD_REASON_LINE_BUSY) { - currentState = VoIPService.STATE_BUSY; - } lockOnScreen = false; boolean animated = previousState != -1; boolean showAcceptDeclineView = false; @@ -1174,6 +1177,36 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification currentUserTextureView.saveCameraLastBitmap(); AndroidUtilities.runOnUIThread(() -> windowView.finish(), 200); 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) { @@ -1222,6 +1255,9 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification if (uiVisible && canHideUI && !hideUiRunnableWaiting && service != null && !service.isMicMute()) { AndroidUtilities.runOnUIThread(hideUIRunnable, 3000); hideUiRunnableWaiting = true; + } else if (service != null && service.isMicMute()) { + AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); + hideUiRunnableWaiting = false; } if (!uiVisible) { statusLayoutOffset -= AndroidUtilities.dp(50); @@ -1394,6 +1430,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification uiVisibilityAnimator.start(); AndroidUtilities.cancelRunOnUIThread(hideUIRunnable); hideUiRunnableWaiting = false; + buttonsLayout.setEnabled(false); } else if (show && !uiVisible) { tapToVideoTooltip.hide(); 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.setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT); uiVisibilityAnimator.start(); + buttonsLayout.setEnabled(true); } uiVisible = show; @@ -1706,7 +1744,7 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification view.announceForAccessibility(text); } serviceInstance.setMicMute(micMute); - updateButtons(true); + updateViewState(); } }); } @@ -1763,7 +1801,11 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification } else if (service.isSpeakerphoneOn()) { speakerPhoneIcon.setImageResource(R.drawable.calls_speaker); } else { - speakerPhoneIcon.setImageResource(R.drawable.calls_menu_phone); + if (service.isHeadsetPlugged()) { + speakerPhoneIcon.setImageResource(R.drawable.calls_menu_headset); + } else { + speakerPhoneIcon.setImageResource(R.drawable.calls_menu_phone); + } } } @@ -1955,6 +1997,19 @@ public class VoIPFragment implements VoIPBaseService.StateListener, Notification 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") private void requestInlinePermissions() { new AlertDialog.Builder(activity).setTitle(LocaleController.getString("AppName", R.string.AppName)) diff --git a/TMessagesProj/src/main/java/org/webrtc/AndroidVideoDecoder.java b/TMessagesProj/src/main/java/org/webrtc/AndroidVideoDecoder.java index 09944c9c2..4a72d1074 100644 --- a/TMessagesProj/src/main/java/org/webrtc/AndroidVideoDecoder.java +++ b/TMessagesProj/src/main/java/org/webrtc/AndroidVideoDecoder.java @@ -21,6 +21,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; + +import org.telegram.messenger.FileLog; import org.webrtc.ThreadUtils.ThreadChecker; /** @@ -543,33 +545,37 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink { VideoFrame.I420Buffer frameBuffer = allocateI420Buffer(width, height); - buffer.limit(yEnd); - buffer.position(yPos); - copyPlane( - buffer.slice(), stride, frameBuffer.getDataY(), frameBuffer.getStrideY(), width, height); + try { //don't crash + buffer.limit(yEnd); + buffer.position(yPos); + copyPlane( + buffer.slice(), stride, frameBuffer.getDataY(), frameBuffer.getStrideY(), width, height); - buffer.limit(uEnd); - buffer.position(uPos); - copyPlane(buffer.slice(), uvStride, frameBuffer.getDataU(), frameBuffer.getStrideU(), - chromaWidth, chromaHeight); - if (sliceHeight % 2 == 1) { - buffer.position(uPos + uvStride * (chromaHeight - 1)); // Seek to beginning of last full row. + buffer.limit(uEnd); + buffer.position(uPos); + copyPlane(buffer.slice(), uvStride, frameBuffer.getDataU(), frameBuffer.getStrideU(), + chromaWidth, chromaHeight); + if (sliceHeight % 2 == 1) { + buffer.position(uPos + uvStride * (chromaHeight - 1)); // Seek to beginning of last full row. - ByteBuffer dataU = frameBuffer.getDataU(); - dataU.position(frameBuffer.getStrideU() * chromaHeight); // Seek to beginning of last row. - dataU.put(buffer); // Copy the last row. - } + ByteBuffer dataU = frameBuffer.getDataU(); + dataU.position(frameBuffer.getStrideU() * chromaHeight); // Seek to beginning of last row. + dataU.put(buffer); // Copy the last row. + } - buffer.limit(vEnd); - buffer.position(vPos); - copyPlane(buffer.slice(), uvStride, frameBuffer.getDataV(), frameBuffer.getStrideV(), - chromaWidth, chromaHeight); - if (sliceHeight % 2 == 1) { - buffer.position(vPos + uvStride * (chromaHeight - 1)); // Seek to beginning of last full row. + buffer.limit(vEnd); + buffer.position(vPos); + copyPlane(buffer.slice(), uvStride, frameBuffer.getDataV(), frameBuffer.getStrideV(), + chromaWidth, chromaHeight); + if (sliceHeight % 2 == 1) { + buffer.position(vPos + uvStride * (chromaHeight - 1)); // Seek to beginning of last full row. - ByteBuffer dataV = frameBuffer.getDataV(); - dataV.position(frameBuffer.getStrideV() * chromaHeight); // Seek to beginning of last row. - dataV.put(buffer); // Copy the last row. + ByteBuffer dataV = frameBuffer.getDataV(); + dataV.position(frameBuffer.getStrideV() * chromaHeight); // Seek to beginning of last row. + dataV.put(buffer); // Copy the last row. + } + } catch (Throwable e) { + FileLog.e(e); } return frameBuffer; diff --git a/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java b/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java index fa6d47667..41e667be8 100644 --- a/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java +++ b/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java @@ -39,7 +39,10 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { // HW H.264 encoder on below devices has poor bitrate control - actual // bitrates deviates a lot from the target value. private static final List 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 VP8_HW_EXCEPTION_MODELS = + Arrays.asList("Pixel 3 XL", "Pixel 3"); @Nullable private final EglBase14.Context sharedContext; private final boolean enableIntelVp8Encoder; @@ -241,6 +244,9 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { } private boolean isHardwareSupportedInCurrentSdkVp8(MediaCodecInfo info) { + if (VP8_HW_EXCEPTION_MODELS.contains(Build.MODEL)) { + return false; + } String name = info.getName(); // QCOM Vp8 encoder is supported in KITKAT or later. return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) diff --git a/TMessagesProj/src/main/java/org/webrtc/TextureBufferImpl.java b/TMessagesProj/src/main/java/org/webrtc/TextureBufferImpl.java index 31d045697..dcf6c8bc2 100644 --- a/TMessagesProj/src/main/java/org/webrtc/TextureBufferImpl.java +++ b/TMessagesProj/src/main/java/org/webrtc/TextureBufferImpl.java @@ -12,6 +12,11 @@ package org.webrtc; import android.graphics.Matrix; import android.os.Handler; + +import org.telegram.messenger.FileLog; + +import java.nio.ByteBuffer; + import androidx.annotation.Nullable; /** @@ -109,8 +114,48 @@ public class TextureBufferImpl implements VideoFrame.TextureBuffer { @Override public VideoFrame.I420Buffer toI420() { - return ThreadUtils.invokeAtFrontUninterruptibly( - toI420Handler, () -> yuvConverter.convert(this)); + try { + return ThreadUtils.invokeAtFrontUninterruptibly( + 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 diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 9a4209832..b5abfa0f3 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -3034,6 +3034,7 @@ Telegram Call Telegram Video Call Earpiece + Headset Speaker Bluetooth Output Devices @@ -3078,6 +3079,7 @@ Accept Decline Retry + Video Message %1$s Voice call %1$s