package org.linphone.sample; import android.annotation.TargetApi; import android.app.Activity; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.TextureView; import android.view.View; import android.widget.RelativeLayout; import androidx.annotation.Nullable; import org.linphone.core.Call; import org.linphone.core.Core; import org.linphone.core.CoreListenerStub; import org.linphone.core.VideoDefinition; import org.linphone.core.tools.Log; import org.linphone.mediastream.Version; public class CallActivity extends Activity { // We use 2 TextureView, one for remote video and one for local camera preview private TextureView mVideoView; private TextureView mCaptureView; private CoreListenerStub mCoreListener; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.call); mVideoView = findViewById(R.id.videoSurface); mCaptureView = findViewById(R.id.videoCaptureSurface); Core core = LinphoneService.getCore(); // We need to tell the core in which to display what core.setNativeVideoWindowId(mVideoView); core.setNativePreviewWindowId(mCaptureView); // Listen for call state changes mCoreListener = new CoreListenerStub() { @Override public void onCallStateChanged(Core core, Call call, Call.State state, String message) { if (state == Call.State.End || state == Call.State.Released) { // Once call is finished (end state), terminate the activity // We also check for released state (called a few seconds later) just in case // we missed the first one finish(); } } }; findViewById(R.id.terminate_call).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Core core = LinphoneService.getCore(); if (core.getCallsNb() > 0) { Call call = core.getCurrentCall(); if (call == null) { // Current call can be null if paused for example call = core.getCalls()[0]; } call.terminate(); } } }); } @Override protected void onStart() { super.onStart(); } @Override protected void onResume() { super.onResume(); LinphoneService.getCore().addListener(mCoreListener); resizePreview(); } @Override protected void onPause() { LinphoneService.getCore().removeListener(mCoreListener); super.onPause(); } @Override protected void onDestroy() { super.onDestroy(); } @TargetApi(24) @Override public void onUserLeaveHint() { // If the device supports Picture in Picture let's use it boolean supportsPip = getPackageManager() .hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE); Log.i("[Call] Is picture in picture supported: " + supportsPip); if (supportsPip && Version.sdkAboveOrEqual(24)) { enterPictureInPictureMode(); } } @Override public void onPictureInPictureModeChanged( boolean isInPictureInPictureMode, Configuration newConfig) { if (isInPictureInPictureMode) { // Currently nothing to do has we only display video // But if we had controls or other UI elements we should hide them } else { // If we did hide something, let's make them visible again } } private void resizePreview() { Core core = LinphoneService.getCore(); if (core.getCallsNb() > 0) { Call call = core.getCurrentCall(); if (call == null) { call = core.getCalls()[0]; } if (call == null) return; DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); int screenHeight = metrics.heightPixels; int maxHeight = screenHeight / 4; // Let's take at most 1/4 of the screen for the camera preview VideoDefinition videoSize = call.getCurrentParams() .getSentVideoDefinition(); // It already takes care of rotation if (videoSize.getWidth() == 0 || videoSize.getHeight() == 0) { Log.w( "[Video] Couldn't get sent video definition, using default video definition"); videoSize = core.getPreferredVideoDefinition(); } int width = videoSize.getWidth(); int height = videoSize.getHeight(); Log.d("[Video] Video height is " + height + ", width is " + width); width = width * maxHeight / height; height = maxHeight; if (mCaptureView == null) { Log.e("[Video] mCaptureView is null !"); return; } RelativeLayout.LayoutParams newLp = new RelativeLayout.LayoutParams(width, height); newLp.addRule( RelativeLayout.ALIGN_PARENT_BOTTOM, 1); // Clears the rule, as there is no removeRule until API 17. newLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 1); mCaptureView.setLayoutParams(newLp); Log.d("[Video] Video preview size set to " + width + "x" + height); } } }