video-straming-android-changes

merge-requests/745/head
mosazaid 5 years ago
parent 95b00dd67d
commit e76ecf172f

@ -70,6 +70,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

@ -2,17 +2,19 @@ package com.hmg.hmgDr
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle
import androidx.annotation.NonNull import androidx.annotation.NonNull
import com.google.gson.GsonBuilder
import com.hmg.hmgDr.Model.GetSessionStatusModel import com.hmg.hmgDr.Model.GetSessionStatusModel
import com.hmg.hmgDr.Model.SessionStatusModel import com.hmg.hmgDr.Model.SessionStatusModel
import com.hmg.hmgDr.ui.VideoCallActivity import io.flutter.embedding.android.FlutterFragment
import com.google.gson.GsonBuilder
import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler { class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler {
private val CHANNEL = "Dr.cloudSolution/videoCall" private val CHANNEL = "Dr.cloudSolution/videoCall"
@ -20,6 +22,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler
private var call: MethodCall? = null private var call: MethodCall? = null
private val LAUNCH_VIDEO: Int = 1 private val LAUNCH_VIDEO: Int = 1
private val flutterFragment: FlutterFragment? = null
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine) GeneratedPluginRegistrant.registerWith(flutterEngine)
@ -27,6 +30,11 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler(this) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler(this)
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
@ -59,15 +67,17 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler
private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?, appLang: String?, baseUrl: String?, sessionStatusModel: GetSessionStatusModel) { private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?, appLang: String?, baseUrl: String?, sessionStatusModel: GetSessionStatusModel) {
// val videoCallActivity = VideoCallActivity() // val videoCallActivity = VideoCallActivity()
val intent = Intent(this, VideoCallActivity::class.java) // val intent = Intent(this, VideoCallActivity::class.java)
intent.putExtra("apiKey", apiKey) // intent.putExtra("apiKey", apiKey)
intent.putExtra("sessionId", sessionId) // intent.putExtra("sessionId", sessionId)
intent.putExtra("token", token) // intent.putExtra("token", token)
intent.putExtra("appLang", appLang) // intent.putExtra("appLang", appLang)
intent.putExtra("baseUrl", baseUrl) // intent.putExtra("baseUrl", baseUrl)
intent.putExtra("sessionStatusModel", sessionStatusModel) // intent.putExtra("sessionStatusModel", sessionStatusModel)
startActivityForResult(intent, LAUNCH_VIDEO) // startActivityForResult(intent, LAUNCH_VIDEO)
val transaction = supportFragmentManager.beginTransaction()
// transaction.add()
} }

@ -0,0 +1,385 @@
package com.hmg.hmgDr.ui.fragment
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
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.widget.*
import androidx.fragment.app.Fragment
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
import com.opentok.android.*
import com.opentok.android.PublisherKit.PublisherListener
import pub.devrel.easypermissions.AfterPermissionGranted
import pub.devrel.easypermissions.AppSettingsDialog
import pub.devrel.easypermissions.EasyPermissions
import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
import java.util.*
class VideoCallFragment : Fragment(), PermissionCallbacks, Session.SessionListener, PublisherListener,
SubscriberKit.VideoListener, VideoCallView {
lateinit var videoCallPresenter: VideoCallPresenter
private var mSession: Session? = null
private var mPublisher: Publisher? = null
private var mSubscriber: Subscriber? = null
private var mVolHandler: Handler? = null
private var mConnectedHandler: Handler? = null
private var mVolRunnable: Runnable? = null
private var mConnectedRunnable: Runnable? = null
private var mPublisherViewContainer: FrameLayout? = null
private var mSubscriberViewContainer: RelativeLayout? = null
private var controlPanel: RelativeLayout? = null
private var apiKey: String? = null
private var sessionId: String? = null
private var token: String? = null
private var appLang: String? = null
private var baseUrl: String? = null
private var isSwitchCameraClicked = false
private var isCameraClicked = false
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 val progressBar: ProgressBar? = null
private val countDownTimer: CountDownTimer? = null
private val progressBarTextView: TextView? = null
private val progressBarLayout: RelativeLayout? = null
private var isConnected = false
private var sessionStatusModel: GetSessionStatusModel? = null
override fun onCreate(savedInstanceState: Bundle?) {
requireActivity().setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
requestPermissions()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.activity_video_call, container, false)
Objects.requireNonNull(requireActivity().actionBar)!!.hide()
initUI(view)
return view
}
override fun onPause() {
super.onPause()
if (mSession == null) {
return
}
mSession!!.onPause()
if (requireActivity().isFinishing) {
disconnectSession()
}
}
override fun onResume() {
super.onResume()
if (mSession == null) {
return
}
mSession!!.onResume()
}
override fun onDestroy() {
disconnectSession()
super.onDestroy()
}
@SuppressLint("ClickableViewAccessibility")
private fun initUI(view: View) {
mPublisherViewContainer = view.findViewById<FrameLayout>(R.id.local_video_view_container)
mSubscriberViewContainer = view.findViewById<RelativeLayout>(R.id.remote_video_view_container)
arguments?.run {
apiKey = getString("apiKey")
sessionId = getString("sessionId")
token = getString("token")
appLang = getString("appLang")
baseUrl = getString("baseUrl")
sessionStatusModel = getParcelable("sessionStatusModel")
}
controlPanel = view.findViewById<RelativeLayout>(R.id.control_panel)
videoCallPresenter = VideoCallPresenterImpl(this, baseUrl)
mCallBtn = view.findViewById<ImageView>(R.id.btn_call)
mCameraBtn = view.findViewById<ImageView>(R.id.btn_camera)
mSwitchCameraBtn = view.findViewById<ImageView>(R.id.btn_switch_camera)
mspeckerBtn = view.findViewById<ImageView>(R.id.btn_specker)
mMicBtn = view.findViewById<ImageView>(R.id.btn_mic)
// progressBarLayout=findViewById(R.id.progressBar);
// progressBar=findViewById(R.id.progress_bar);
// progressBarTextView=findViewById(R.id.progress_bar_text);
// progressBar.setVisibility(View.GONE);
hiddenButtons()
checkClientConnected()
mSubscriberViewContainer!!.setOnTouchListener { v: View?, event: MotionEvent? ->
controlPanel!!.visibility = View.VISIBLE
mVolHandler!!.removeCallbacks(mVolRunnable!!)
mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
true
}
if (appLang == "ar") {
progressBarLayout!!.layoutDirection = View.LAYOUT_DIRECTION_RTL
}
}
private fun checkClientConnected() {
mConnectedHandler = Handler((Looper.getMainLooper()))
mConnectedRunnable = Runnable {
if (!isConnected) {
videoCallPresenter.callClintConnected(sessionStatusModel)
}
}
mConnectedHandler!!.postDelayed(mConnectedRunnable!!, (55 * 1000).toLong())
}
private fun hiddenButtons() {
mVolHandler = Handler()
mVolRunnable = Runnable { controlPanel!!.visibility = View.GONE }
mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
override fun onPermissionsGranted(requestCode: Int, perms: List<String?>) {
Log.d(TAG, "onPermissionsGranted:" + requestCode + ":" + perms.size)
}
override fun onPermissionsDenied(requestCode: Int, perms: List<String?>) {
Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size)
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
AppSettingsDialog.Builder(this)
.setTitle(getString(R.string.title_settings_dialog))
.setRationale(getString(R.string.rationale_ask_again))
.setPositiveButton(getString(R.string.setting))
.setNegativeButton(getString(R.string.cancel))
.setRequestCode(RC_SETTINGS_SCREEN_PERM)
.build()
.show()
}
}
@AfterPermissionGranted(RC_VIDEO_APP_PERM)
private fun requestPermissions() {
val perms = arrayOf(Manifest.permission.INTERNET, Manifest.permission.CAMERA)
if (EasyPermissions.hasPermissions(requireContext(), *perms)) {
try {
mSession = Session.Builder(context, apiKey, sessionId).build()
mSession!!.setSessionListener(this)
mSession!!.connect(token)
} catch (e: Exception) {
e.printStackTrace()
}
} else {
EasyPermissions.requestPermissions(this, getString(R.string.remaining_ar), RC_VIDEO_APP_PERM, *perms)
}
}
override fun onConnected(session: Session?) {
Log.i(TAG, "Session Connected")
mPublisher = Publisher.Builder(requireContext()).build()
mPublisher!!.setPublisherListener(this)
mPublisherViewContainer!!.addView(mPublisher!!.view)
if (mPublisher!!.getView() is GLSurfaceView) {
(mPublisher!!.getView() as GLSurfaceView).setZOrderOnTop(true)
}
mSession!!.publish(mPublisher)
}
override fun onDisconnected(session: Session) {
Log.d(TAG, "onDisconnected: disconnected from session " + session.sessionId)
mSession = null
}
override fun onError(session: Session, opentokError: OpentokError) {
Log.d(TAG, "onError: Error (" + opentokError.message + ") in session " + session.sessionId)
Toast.makeText(requireContext(), "Session error. See the logcat please.", Toast.LENGTH_LONG).show()
requireActivity().finish()
}
override fun onStreamReceived(session: Session, stream: Stream) {
Log.d(TAG, "onStreamReceived: New stream " + stream.streamId + " in session " + session.sessionId)
if (mSubscriber != null) {
isConnected = true
return
}
isConnected = true
subscribeToStream(stream)
videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(3, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid))
}
override fun onStreamDropped(session: Session, stream: Stream) {
Log.d(TAG, "onStreamDropped: Stream " + stream.streamId + " dropped from session " + session.sessionId)
if (mSubscriber == null) {
return
}
if (mSubscriber!!.stream == stream) {
mSubscriberViewContainer!!.removeView(mSubscriber!!.view)
mSubscriber!!.destroy()
mSubscriber = null
}
disconnectSession()
}
override fun onStreamCreated(publisherKit: PublisherKit?, stream: Stream) {
Log.d(TAG, "onStreamCreated: Own stream " + stream.streamId + " created")
}
override fun onStreamDestroyed(publisherKit: PublisherKit?, stream: Stream) {
Log.d(TAG, "onStreamDestroyed: Own stream " + stream.streamId + " destroyed")
}
override fun onError(publisherKit: PublisherKit?, opentokError: OpentokError) {
Log.d(VideoCallFragment.TAG, "onError: Error (" + opentokError.message + ") in publisher")
Toast.makeText(requireContext(), "Session error. See the logcat please.", Toast.LENGTH_LONG).show()
requireActivity().finish()
}
override fun onVideoDataReceived(subscriberKit: SubscriberKit?) {
mSubscriber!!.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL)
mSubscriberViewContainer!!.addView(mSubscriber!!.view)
}
override fun onVideoDisabled(subscriberKit: SubscriberKit?, s: String?) {}
override fun onVideoEnabled(subscriberKit: SubscriberKit?, s: String?) {}
override fun onVideoDisableWarning(subscriberKit: SubscriberKit?) {}
override fun onVideoDisableWarningLifted(subscriberKit: SubscriberKit?) {}
private fun subscribeToStream(stream: Stream) {
mSubscriber = Subscriber.Builder(requireContext(), stream).build()
mSubscriber!!.setVideoListener(this)
mSession!!.subscribe(mSubscriber)
}
private fun disconnectSession() {
if (mSession == null) {
requireActivity().setResult(Activity.RESULT_CANCELED)
requireActivity().finish()
return
}
if (mSubscriber != null) {
mSubscriberViewContainer!!.removeView(mSubscriber!!.view)
mSession!!.unsubscribe(mSubscriber)
mSubscriber!!.destroy()
mSubscriber = null
}
if (mPublisher != null) {
mPublisherViewContainer!!.removeView(mPublisher!!.view)
mSession!!.unpublish(mPublisher)
mPublisher!!.destroy()
mPublisher = null
}
mSession!!.disconnect()
countDownTimer?.cancel()
videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(16, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid))
requireActivity().finish()
}
fun onSwitchCameraClicked(view: View?) {
if (mPublisher != null) {
isSwitchCameraClicked = !isSwitchCameraClicked
mPublisher!!.cycleCamera()
val res = if (isSwitchCameraClicked) R.drawable.flip_disapled else R.drawable.flip_enabled
mSwitchCameraBtn!!.setImageResource(res)
}
}
fun onCameraClicked(view: View?) {
if (mPublisher != null) {
isCameraClicked = !isCameraClicked
mPublisher!!.publishVideo = !isCameraClicked
val res = if (isCameraClicked) R.drawable.video_disanabled else R.drawable.video_enabled
mCameraBtn!!.setImageResource(res)
}
}
fun onSpeckerClicked(view: View?) {
if (mSubscriber != null) {
isSpeckerClicked = !isSpeckerClicked
mSubscriber!!.subscribeToAudio = !isSpeckerClicked
val res = if (isSpeckerClicked) R.drawable.audio_disabled else R.drawable.audio_enabled
mspeckerBtn!!.setImageResource(res)
}
}
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 onCallClicked(view: View?) {
disconnectSession()
}
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() {}
companion object {
@JvmStatic
fun newInstance(args: Bundle) =
VideoCallFragment().apply {
arguments = args
}
private val TAG = VideoCallActivity::class.java.simpleName
private const val RC_SETTINGS_SCREEN_PERM = 123
private const val RC_VIDEO_APP_PERM = 124
}
}

@ -4,5 +4,7 @@
<string name="remaining_ar">الوقت المتبقي بالثانيه: </string> <string name="remaining_ar">الوقت المتبقي بالثانيه: </string>
<string name="setting">Settings</string> <string name="setting">Settings</string>
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources> </resources>

@ -587,7 +587,7 @@ packages:
name: js name: js
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.3-nullsafety.1" version: "0.6.2"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:

Loading…
Cancel
Save