diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt index b57f5732..f013d281 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt @@ -7,7 +7,7 @@ import androidx.annotation.NonNull import com.google.gson.GsonBuilder import com.hmg.hmgDr.Model.GetSessionStatusModel import com.hmg.hmgDr.Model.SessionStatusModel -import io.flutter.embedding.android.FlutterFragment +import com.hmg.hmgDr.ui.fragment.VideoCallFragment import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall @@ -22,7 +22,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler private var call: MethodCall? = null private val LAUNCH_VIDEO: Int = 1 - private val flutterFragment: FlutterFragment? = null + lateinit var dialogFragment: VideoCallFragment override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine) @@ -78,7 +78,9 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler // startActivityForResult(intent, LAUNCH_VIDEO) val transaction = supportFragmentManager.beginTransaction() -// transaction.add() + dialogFragment = VideoCallFragment.newInstance(Bundle()) + dialogFragment.isCancelable = false + dialogFragment.show(transaction, "dialog") } diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/VideoCallActivity.java b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/VideoCallActivity.java index be4ebfb8..0fb061f1 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/VideoCallActivity.java +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/VideoCallActivity.java @@ -411,10 +411,6 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi finish(); } - public void onMinimizedClicked(View view) { - - } - public void onSwitchCameraClicked(View view) { if (mPublisher != null) { isSwitchCameraClicked = !isSwitchCameraClicked; @@ -424,6 +420,14 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi } } + public void onCallClicked(View view) { + disconnectSession(); + } + + public void onMinimizedClicked(View view) { + + } + public void onCameraClicked(View view) { if (mPublisher != null) { isCameraClicked = !isCameraClicked; @@ -433,15 +437,6 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi } } - public void onSpeckerClicked(View view) { - if (mSubscriber != null) { - isSpeckerClicked = !isSpeckerClicked; - mSubscriber.setSubscribeToAudio(!isSpeckerClicked); - int res = isSpeckerClicked ? R.drawable.audio_disabled : R.drawable.audio_enabled; - mspeckerBtn.setImageResource(res); - } - } - public void onMicClicked(View view) { if (mPublisher != null) { @@ -452,8 +447,13 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi } } - public void onCallClicked(View view) { - disconnectSession(); + public void onSpeckerClicked(View view) { + if (mSubscriber != null) { + isSpeckerClicked = !isSpeckerClicked; + mSubscriber.setSubscribeToAudio(!isSpeckerClicked); + int res = isSpeckerClicked ? R.drawable.audio_disabled : R.drawable.audio_enabled; + mspeckerBtn.setImageResource(res); + } } @Override diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt index be343b89..d5a5d5da 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt @@ -3,24 +3,26 @@ package com.hmg.hmgDr.ui.fragment import android.Manifest import android.annotation.SuppressLint import android.app.Activity +import android.app.Dialog +import android.content.Context import android.content.Intent +import android.graphics.Color +import android.graphics.Point +import android.graphics.drawable.ColorDrawable import android.opengl.GLSurfaceView import android.os.Bundle import android.os.CountDownTimer import android.os.Handler import android.os.Looper import android.util.Log -import android.view.LayoutInflater -import android.view.MotionEvent -import android.view.View -import android.view.ViewGroup +import android.view.* import android.widget.* -import androidx.fragment.app.Fragment +import androidx.annotation.Nullable +import androidx.fragment.app.DialogFragment import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel import com.hmg.hmgDr.Model.GetSessionStatusModel import com.hmg.hmgDr.Model.SessionStatusModel import com.hmg.hmgDr.R -import com.hmg.hmgDr.ui.VideoCallActivity import com.hmg.hmgDr.ui.VideoCallContract.VideoCallPresenter import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView import com.hmg.hmgDr.ui.VideoCallPresenterImpl @@ -31,10 +33,20 @@ import pub.devrel.easypermissions.AppSettingsDialog import pub.devrel.easypermissions.EasyPermissions import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks import java.util.* +import kotlin.math.ceil -class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListener, PublisherListener, +class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener, PublisherListener, SubscriberKit.VideoListener, VideoCallView { + var isFullScreen: Boolean = true + private var x_init_cord = 0 + private var y_init_cord:Int = 0 + private var x_init_margin:Int = 0 + private var y_init_margin:Int = 0 + private val szWindow: Point = Point() + private lateinit var mWindowManager: WindowManager + private var isLeft = true + lateinit var videoCallPresenter: VideoCallPresenter private var mSession: Session? = null @@ -61,11 +73,13 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen private var isSpeckerClicked = false private var isMicClicked = false - private var mCallBtn: ImageView? = null - private var mCameraBtn: ImageView? = null - private var mSwitchCameraBtn: ImageView? = null - private var mspeckerBtn: ImageView? = null - private var mMicBtn: ImageView? = null + private lateinit var videoCallContainer: LinearLayout + private lateinit var mCallBtn: ImageView + private lateinit var btnMinimize: ImageView + private lateinit var mCameraBtn: ImageView + private lateinit var mSwitchCameraBtn: ImageView + private lateinit var mspeckerBtn: ImageView + private lateinit var mMicBtn: ImageView private val progressBar: ProgressBar? = null private val countDownTimer: CountDownTimer? = null @@ -84,6 +98,45 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen requestPermissions() } + override fun onStart() { + super.onStart() + + dialog?.window?.setLayout( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT + ) + } + + override fun getTheme(): Int { + return R.style.dialogTheme + } + + override fun onCreateDialog(@Nullable savedInstanceState: Bundle?): Dialog { + val dialog: Dialog = super.onCreateDialog(savedInstanceState) + return dialog + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // This is done in a post() since the dialog must be drawn before locating. + requireView().post { + val dialogWindow = dialog!!.window + + if (dialog != null && dialogWindow != null) { + dialogWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)); + } + + // Make the dialog possible to be outside touch + dialogWindow!!.setFlags( + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + ) + dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + requireView().invalidate() + } + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -91,6 +144,7 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen Objects.requireNonNull(requireActivity().actionBar)!!.hide() initUI(view) + handleDragDialog() return view } @@ -121,6 +175,7 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen @SuppressLint("ClickableViewAccessibility") private fun initUI(view: View) { + videoCallContainer = view.findViewById(R.id.video_call_ll) mPublisherViewContainer = view.findViewById(R.id.local_video_view_container) mSubscriberViewContainer = view.findViewById(R.id.remote_video_view_container) @@ -136,11 +191,29 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen controlPanel = view.findViewById(R.id.control_panel) videoCallPresenter = VideoCallPresenterImpl(this, baseUrl) mCallBtn = view.findViewById(R.id.btn_call) + mCallBtn.setOnClickListener { + onCallClicked(it) + } + btnMinimize = view.findViewById(R.id.btn_minimize) + btnMinimize.setOnClickListener { + onMinimizedClicked(it) + } mCameraBtn = view.findViewById(R.id.btn_camera) + mCameraBtn.setOnClickListener { + onCameraClicked(it) + } mSwitchCameraBtn = view.findViewById(R.id.btn_switch_camera) + mSwitchCameraBtn.setOnClickListener { + onSwitchCameraClicked(it) + } mspeckerBtn = view.findViewById(R.id.btn_specker) + mspeckerBtn.setOnClickListener { + onSpeckerClicked(it) + } mMicBtn = view.findViewById(R.id.btn_mic) - + mMicBtn.setOnClickListener { + onMicClicked(it) + } // progressBarLayout=findViewById(R.id.progressBar); // progressBar=findViewById(R.id.progress_bar); // progressBarTextView=findViewById(R.id.progress_bar_text); @@ -316,6 +389,20 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen requireActivity().finish() } + + override fun onCallSuccessful(sessionStatusModel: SessionStatusModel) { + if (sessionStatusModel.sessionStatus == 2 || sessionStatusModel.sessionStatus == 3) { + val returnIntent = Intent() + returnIntent.putExtra("sessionStatusNotRespond", sessionStatusModel) + requireActivity().setResult(Activity.RESULT_OK, returnIntent) + requireActivity().finish() + } + } + + override fun onCallChangeCallStatusSuccessful(sessionStatusModel: SessionStatusModel?) {} + + override fun onFailure() {} + fun onSwitchCameraClicked(view: View?) { if (mPublisher != null) { isSwitchCameraClicked = !isSwitchCameraClicked @@ -325,6 +412,25 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen } } + fun onCallClicked(view: View?) { + disconnectSession() + } + + fun onMinimizedClicked(view: View?) { + if (isFullScreen) { + dialog?.window?.setLayout( + 400, + 600 + ) + } else { + dialog?.window?.setLayout( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT + ) + } + isFullScreen = !isFullScreen + } + fun onCameraClicked(view: View?) { if (mPublisher != null) { isCameraClicked = !isCameraClicked @@ -334,6 +440,15 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen } } + fun onMicClicked(view: View?) { + if (mPublisher != null) { + isMicClicked = !isMicClicked + mPublisher!!.publishAudio = !isMicClicked + val res = if (isMicClicked) R.drawable.mic_disabled else R.drawable.mic_enabled + mMicBtn!!.setImageResource(res) + } + } + fun onSpeckerClicked(view: View?) { if (mSubscriber != null) { isSpeckerClicked = !isSpeckerClicked @@ -343,31 +458,144 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen } } - fun onMicClicked(view: View?) { - if (mPublisher != null) { - isMicClicked = !isMicClicked - mPublisher!!.publishAudio = !isMicClicked - val res = if (isMicClicked) R.drawable.mic_disabled else R.drawable.mic_enabled - mMicBtn!!.setImageResource(res) + @SuppressLint("ClickableViewAccessibility") + fun handleDragDialog(){ + mWindowManager = requireActivity().getSystemService(Context.WINDOW_SERVICE) as WindowManager + getWindowManagerDefaultDisplay() + + videoCallContainer.setOnTouchListener { _, event -> + //Get Floating widget view params + //Get Floating widget view params + val layoutParams : WindowManager.LayoutParams = dialog!!.window!!.attributes + //get the touch location coordinates + val x_cord = event.rawX.toInt() + val y_cord = event.rawY.toInt() + val x_cord_Destination: Int + var y_cord_Destination: Int + + when (event.action) { + MotionEvent.ACTION_DOWN -> { + x_init_cord = x_cord + y_init_cord = y_cord + + //remember the initial position. + x_init_margin = layoutParams.x + y_init_margin = layoutParams.y + } + MotionEvent.ACTION_UP -> { + //Get the difference between initial coordinate and current coordinate + val x_diff: Int = x_cord - x_init_cord + val y_diff: Int = y_cord - y_init_cord + + y_cord_Destination = y_init_margin + y_diff + val barHeight: Int = getStatusBarHeight() + if (y_cord_Destination < 0) { +// y_cord_Destination = 0 + y_cord_Destination = + -(szWindow.y - (videoCallContainer.height /*+ barHeight*/)) + } else if (y_cord_Destination + (videoCallContainer.height + barHeight) > szWindow.y) { + y_cord_Destination = + szWindow.y - (videoCallContainer.height + barHeight) + } + layoutParams.y = y_cord_Destination + + //reset position if user drags the floating view + resetPosition(x_cord) + } + MotionEvent.ACTION_MOVE -> { + val x_diff_move: Int = x_cord - x_init_cord + val y_diff_move: Int = y_cord - y_init_cord + x_cord_Destination = x_init_margin + x_diff_move + y_cord_Destination = y_init_margin + y_diff_move + + layoutParams.x = x_cord_Destination + layoutParams.y = y_cord_Destination + + dialog!!.window!!.attributes = layoutParams + } + } + true } } - fun onCallClicked(view: View?) { - disconnectSession() + /* Reset position of Floating Widget view on dragging */ + private fun resetPosition(x_cord_now: Int) { + if (x_cord_now <= szWindow.x / 2) { + isLeft = true + moveToLeft(x_cord_now) + } else { + isLeft = false + moveToRight(x_cord_now) + } } - override fun onCallSuccessful(sessionStatusModel: SessionStatusModel) { - if (sessionStatusModel.sessionStatus == 2 || sessionStatusModel.sessionStatus == 3) { - val returnIntent = Intent() - returnIntent.putExtra("sessionStatusNotRespond", sessionStatusModel) - requireActivity().setResult(Activity.RESULT_OK, returnIntent) - requireActivity().finish() - } + /* Method to move the Floating widget view to Left */ + private fun moveToLeft(current_x_cord: Int) { + + var mParams : WindowManager.LayoutParams = dialog!!.window!!.attributes + + mParams.x = + (szWindow.x - current_x_cord * current_x_cord - videoCallContainer.width).toInt() + + dialog!!.window!!.attributes = mParams + val x = szWindow.x - current_x_cord + object : CountDownTimer(500, 5) { + //get params of Floating Widget view + var mParams : WindowManager.LayoutParams = dialog!!.window!!.attributes + override fun onTick(t: Long) { + val step = (500 - t) / 5 + // mParams.x = 0 - (current_x_cord * current_x_cord * step).toInt() + mParams.x = + (szWindow.x - current_x_cord * current_x_cord * step - videoCallContainer.width).toInt() + + dialog!!.window!!.attributes = mParams + } + + override fun onFinish() { + mParams.x = -(szWindow.x - videoCallContainer.width) + + dialog!!.window!!.attributes = mParams + } + }.start() } - override fun onCallChangeCallStatusSuccessful(sessionStatusModel: SessionStatusModel?) {} + /* Method to move the Floating widget view to Right */ + private fun moveToRight(current_x_cord: Int) { +// var mParams : WindowManager.LayoutParams = dialog!!.window!!.attributes +// mParams.x = +// (szWindow.x + current_x_cord * current_x_cord - videoCallContainer.width).toInt() +// +// dialog!!.window!!.attributes = mParams + object : CountDownTimer(500, 5) { + //get params of Floating Widget view + var mParams : WindowManager.LayoutParams = dialog!!.window!!.attributes + override fun onTick(t: Long) { + val step = (500 - t) / 5 + mParams.x = + (szWindow.x + current_x_cord * current_x_cord * step - videoCallContainer.width).toInt() + + dialog!!.window!!.attributes = mParams + } - override fun onFailure() {} + override fun onFinish() { + mParams.x = szWindow.x - videoCallContainer.width + + dialog!!.window!!.attributes = mParams + } + }.start() + } + + private fun getWindowManagerDefaultDisplay() { + mWindowManager.getDefaultDisplay() + .getSize(szWindow) + } + + /* return status bar height on basis of device display metrics */ + private fun getStatusBarHeight(): Int { + return ceil( + (25 * requireActivity().applicationContext.resources.displayMetrics.density).toDouble() + ).toInt() + } companion object { @JvmStatic @@ -376,7 +604,7 @@ class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListen arguments = args } - private val TAG = VideoCallActivity::class.java.simpleName + private val TAG = VideoCallFragment::class.java.simpleName private const val RC_SETTINGS_SCREEN_PERM = 123 private const val RC_VIDEO_APP_PERM = 124 diff --git a/android/app/src/main/res/layout/activity_video_call.xml b/android/app/src/main/res/layout/activity_video_call.xml index a3c2ced1..b7ca8d8d 100644 --- a/android/app/src/main/res/layout/activity_video_call.xml +++ b/android/app/src/main/res/layout/activity_video_call.xml @@ -1,6 +1,7 @@ @@ -132,7 +132,6 @@ android:layout_width="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size" android:layout_alignParentEnd="true" - android:onClick="onCallClicked" android:scaleType="centerCrop" android:src="@drawable/call" /> @@ -141,7 +140,6 @@ android:layout_width="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size" android:layout_alignParentStart="true" - android:onClick="onMinimizedClicked" android:layout_marginEnd="@dimen/padding_space_small" android:scaleType="centerCrop" android:src="@drawable/ic_mini" /> @@ -151,7 +149,6 @@ android:layout_width="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size" android:layout_toEndOf="@id/btn_minimize" - android:onClick="onCameraClicked" android:scaleType="centerCrop" android:layout_marginEnd="@dimen/padding_space_small" android:src="@drawable/video_enabled" /> @@ -161,7 +158,6 @@ android:layout_width="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size" android:layout_toEndOf="@id/btn_camera" - android:onClick="onMicClicked" android:layout_marginEnd="@dimen/padding_space_small" android:scaleType="centerCrop" android:src="@drawable/mic_enabled" /> @@ -171,7 +167,6 @@ android:layout_width="@dimen/video_icon_size" android:layout_height="@dimen/video_icon_size" android:layout_toEndOf="@id/btn_mic" - android:onClick="onSpeckerClicked" android:scaleType="centerCrop" android:layout_marginEnd="@dimen/padding_space_small" android:src="@drawable/audio_enabled" /> diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 24355fae..e13b5b14 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -16,4 +16,21 @@ true @null + + +