make floating video screen

video-stream-floating
mosazaid 5 years ago
parent 8bfb37d4c0
commit 7cc25f6101

@ -12,6 +12,9 @@
<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.CALL_PHONE" />
<!-- Permission required to draw floating widget over other apps -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
@ -41,7 +44,13 @@
</intent-filter> </intent-filter>
</activity> </activity>
<service android:name = ".Service.VideoStreamContainerService"/> <!-- <service android:name = ".Service.VideoStreamContainerService"-->
<!-- android:enabled="true"-->
<!-- android:exported="false"/>-->
<service android:name = ".Service.VideoStreamFloatingWidgetService"
android:enabled="true"
android:exported="false"/>
<!-- <!--
Don't delete the meta-data below. Don't delete the meta-data below.

@ -5,18 +5,20 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.provider.Settings
import android.util.Log import android.util.Log
import android.view.inputmethod.InputMethodManager import android.widget.Toast
import android.widget.EditText
import androidx.annotation.NonNull import androidx.annotation.NonNull
import com.google.gson.GsonBuilder 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.Service.VideoStreamContainerService import com.hmg.hmgDr.Service.VideoStreamContainerService
import com.hmg.hmgDr.Service.VideoStreamFloatingWidgetService
import com.hmg.hmgDr.ui.VideoCallResponseListener import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
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
@ -27,15 +29,17 @@ import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler, class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
VideoCallResponseListener { VideoCallResponseListener {
/* Permission request code to draw over other apps */
private val DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE = 1222
private val CHANNEL = "Dr.cloudSolution/videoCall" private val CHANNEL = "Dr.cloudSolution/videoCall"
private lateinit var methodChannel: MethodChannel private lateinit var methodChannel: MethodChannel
private var result: MethodChannel.Result? = null private var result: MethodChannel.Result? = null
private var call: MethodCall? = null private var call: MethodCall? = null
private val LAUNCH_VIDEO: Int = 1 private val LAUNCH_VIDEO: Int = 1
private var dialogFragment: VideoCallFragment? = null
private var serviceIntent: Intent? = null private var serviceIntent: Intent? = null
private var videoStreamService: VideoStreamContainerService? = null private var videoStreamService: VideoStreamFloatingWidgetService? = null
private var bound = false private var bound = false
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
@ -67,15 +71,21 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
val isRecording = call.argument<Boolean>("isRecording") val isRecording = call.argument<Boolean>("isRecording")
val sessionStatusModel = val sessionStatusModel =
GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName, isRecording!!) GetSessionStatusModel(
VC_ID,
tokenID,
generalId,
doctorId,
patientName,
isRecording!!
)
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel) openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
} }
"closeVideoCall" -> { "closeVideoCall" -> {
dialogFragment?.onCallClicked() videoStreamService?.closeVideoCall()
// videoStreamService?.closeVideoCall()
} }
"onCallConnected" -> { "onCallConnected" -> {
@ -86,91 +96,97 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
} }
} }
private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?, appLang: String?, baseUrl: String?, sessionStatusModel: GetSessionStatusModel) { private fun openVideoCall(
if (dialogFragment == null) { apiKey: String?,
val arguments = Bundle() sessionId: String?,
arguments.putString("apiKey", apiKey) token: String?,
arguments.putString("sessionId", sessionId) appLang: String?,
arguments.putString("token", token) baseUrl: String?,
arguments.putString("appLang", appLang) sessionStatusModel: GetSessionStatusModel
arguments.putString("baseUrl", baseUrl) ) {
arguments.putParcelable("sessionStatusModel", sessionStatusModel)
val arguments = Bundle()
val transaction = supportFragmentManager.beginTransaction() arguments.putString("apiKey", apiKey)
dialogFragment = VideoCallFragment.newInstance(arguments) arguments.putString("sessionId", sessionId)
dialogFragment?.let { arguments.putString("token", token)
it.setCallListener(this) arguments.putString("appLang", appLang)
it.isCancelable = true arguments.putString("baseUrl", baseUrl)
if (it.isAdded){ arguments.putParcelable("sessionStatusModel", sessionStatusModel)
it.dismiss()
}else { // start service
it.show(transaction, "dialog") // serviceIntent = Intent(this@MainActivity, VideoStreamContainerService::class.java)
} serviceIntent = Intent(this@MainActivity, VideoStreamFloatingWidgetService::class.java)
serviceIntent?.run {
putExtras(arguments)
}
checkFloatingWidgetPermission()
}
} private fun checkFloatingWidgetPermission() {
} else if (!dialogFragment!!.isVisible) { //Check if the application has draw over other apps permission or not?
val transaction = supportFragmentManager.beginTransaction() //This permission is by default available for API<23. But for API > 23
dialogFragment!!.show(transaction, "dialog") //you have to ask for the permission in runtime.
//Check if the application has draw over other apps permission or not?
//This permission is by default available for API<23. But for API > 23
//you have to ask for the permission in runtime.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
//If the draw over permission is not available open the settings screen
//to grant the permission.
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:$packageName")
)
startActivityForResult(intent, DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE)
} else { //If permission is granted start floating widget service
startFloatingWidgetService()
} }
} }
// private fun openVideoCall( private fun startFloatingWidgetService() {
// apiKey: String?, startService(serviceIntent)
// sessionId: String?, bindService()
// token: String?, }
// appLang: String?,
// baseUrl: String?,
// sessionStatusModel: GetSessionStatusModel
// ) {
//
// val arguments = Bundle()
// arguments.putString("apiKey", apiKey)
// arguments.putString("sessionId", sessionId)
// arguments.putString("token", token)
// arguments.putString("appLang", appLang)
// arguments.putString("baseUrl", baseUrl)
// arguments.putParcelable("sessionStatusModel", sessionStatusModel)
//
//// showSoftKeyBoard(null)
// // start service
// serviceIntent = Intent(this@MainActivity, VideoStreamContainerService::class.java)
// serviceIntent?.run {
// putExtras(arguments)
// startService(this)
// }
//// bindService()
// }
/* override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) /*if (requestCode == LAUNCH_VIDEO) {
var asd = ""; if (resultCode == Activity.RESULT_OK) {
if (requestCode == LAUNCH_VIDEO) { val result : SessionStatusModel? = data?.getParcelableExtra("sessionStatusNotRespond")
if (resultCode == Activity.RESULT_OK) { val callResponse : HashMap<String, String> = HashMap()
val result : SessionStatusModel? = data?.getParcelableExtra("sessionStatusNotRespond")
val callResponse : HashMap<String, String> = HashMap()
val sessionStatus : HashMap<String, String> = HashMap() val sessionStatus : HashMap<String, String> = HashMap()
val gson = GsonBuilder().serializeNulls().create() val gson = GsonBuilder().serializeNulls().create()
callResponse["callResponse"] = "CallNotRespond" callResponse["callResponse"] = "CallNotRespond"
val jsonRes = gson.toJson(result) val jsonRes = gson.toJson(result)
callResponse["sessionStatus"] = jsonRes callResponse["sessionStatus"] = jsonRes
this.result?.success(callResponse) this.result?.success(callResponse)
} }
if (resultCode == Activity.RESULT_CANCELED) { if (resultCode == Activity.RESULT_CANCELED) {
val callResponse : HashMap<String, String> = HashMap() val callResponse : HashMap<String, String> = HashMap()
callResponse["callResponse"] = "CallEnd" callResponse["callResponse"] = "CallEnd"
result?.success(callResponse) result?.success(callResponse)
} }
} } else*/ if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) {
}*/ //Check if the permission is granted or not.
if (resultCode == RESULT_OK)
//If permission granted start floating widget service
startFloatingWidgetService()
else
//Permission is not available then display toast
Toast.makeText(
this,
"Draw over other app permission not available. App won\\'t work without permission. Please try again.",
Toast.LENGTH_SHORT
).show()
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
override fun onCallFinished(resultCode: Int, intent: Intent?) { override fun onCallFinished(resultCode: Int, intent: Intent?) {
dialogFragment = null
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
val result: SessionStatusModel? = intent?.getParcelableExtra("sessionStatusNotRespond") val result: SessionStatusModel? = intent?.getParcelableExtra("sessionStatusNotRespond")
val callResponse: HashMap<String, String> = HashMap() val callResponse: HashMap<String, String> = HashMap()
@ -197,14 +213,9 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
} }
} }
// stopService(serviceIntent) stopService(serviceIntent)
// unbindService() unbindService()
// videoStreamService!!.serviceRunning = false videoStreamService!!.serviceRunning = false
}
override fun errorHandle(message: String) {
dialogFragment = null
// Toast.makeText(this, message, Toast.LENGTH_LONG).show()
} }
override fun minimizeVideoEvent(isMinimize: Boolean) { override fun minimizeVideoEvent(isMinimize: Boolean) {
@ -228,53 +239,41 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
// unbindService() // unbindService()
// } // }
// private fun bindService() { private fun bindService() {
// serviceIntent?.run { serviceIntent?.run {
// if (videoStreamService != null && !videoStreamService!!.serviceRunning){ if (videoStreamService != null && !videoStreamService!!.serviceRunning) {
// startService(this) startService(this)
// } }
// bindService(this, serviceConnection, Context.BIND_AUTO_CREATE) bindService(this, serviceConnection, Context.BIND_AUTO_CREATE)
// videoStreamService?.serviceRunning = true videoStreamService?.serviceRunning = true
// } }
// } }
//
// private fun unbindService() { private fun unbindService() {
// if (bound) { if (bound) {
// videoStreamService!!.videoCallResponseListener = null // unregister videoStreamService!!.videoCallResponseListener = null // unregister
// videoStreamService!!.mActivity = null // videoStreamService!!.mActivity = null
// unbindService(serviceConnection) unbindService(serviceConnection)
// bound = false bound = false
// } }
// } }
//
// private val serviceConnection: ServiceConnection = object : ServiceConnection { private val serviceConnection: ServiceConnection = object : ServiceConnection {
// override fun onServiceConnected(name: ComponentName?, service: IBinder?) { override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// val binder: VideoStreamContainerService.VideoStreamBinder = // val binder: VideoStreamContainerService.VideoStreamBinder =
// service as VideoStreamContainerService.VideoStreamBinder // service as VideoStreamContainerService.VideoStreamBinder
// videoStreamService = binder.service val binder: VideoStreamFloatingWidgetService.VideoStreamBinder =
// bound = true service as VideoStreamFloatingWidgetService.VideoStreamBinder
// videoStreamService!!.videoCallResponseListener = this@MainActivity // register videoStreamService = binder.service
bound = true
videoStreamService!!.videoCallResponseListener = this@MainActivity // register
// videoStreamService!!.mActivity = this@MainActivity // register // videoStreamService!!.mActivity = this@MainActivity // register
// } }
//
// override fun onServiceDisconnected(name: ComponentName?) {
// bound = false
// }
//
// }
// code to hide soft keyboard
fun hideSoftKeyBoard(editBox: EditText?) {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editBox?.windowToken, 0)
}
override fun onServiceDisconnected(name: ComponentName?) {
bound = false
}
// code to show soft keyboard
private fun showSoftKeyBoard(editBox: EditText?) {
val inputMethodManager = this.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
editBox?.requestFocus()
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
} }
} }

@ -98,16 +98,17 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
private lateinit var mSwitchCameraBtn: ImageView private lateinit var mSwitchCameraBtn: ImageView
private lateinit var mspeckerBtn: ImageView private lateinit var mspeckerBtn: ImageView
private lateinit var mMicBtn: ImageView private lateinit var mMicBtn: ImageView
private lateinit var patientName: TextView private lateinit var patientName: TextView
private lateinit var cmTimer: Chronometer private lateinit var cmTimer: Chronometer
private var elapsedTime: Long = 0 private var elapsedTime: Long = 0
private var resume = false private var resume = false
private val progressBar: ProgressBar? = null private val progressBar: ProgressBar? = null
private val countDownTimer: CountDownTimer? = null private val countDownTimer: CountDownTimer? = null
private val progressBarTextView: TextView? = null private val progressBarTextView: TextView? = null
private val progressBarLayout: RelativeLayout? = null private val
progressBarLayout: RelativeLayout? = null
private var isConnected = false private var isConnected = false

@ -2,6 +2,9 @@ package com.hmg.hmgDr.util
import android.content.Context import android.content.Context
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import io.flutter.embedding.android.FlutterFragmentActivity
object ViewsUtil { object ViewsUtil {
@ -30,4 +33,18 @@ object ViewsUtil {
displayMetrics.widthPixels.toFloat() displayMetrics.widthPixels.toFloat()
} }
} }
// code to hide soft keyboard
fun hideSoftKeyBoard(context: Context, editBox: EditText?) {
val imm = context.getSystemService(FlutterFragmentActivity.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editBox?.windowToken, 0)
}
// code to show soft keyboard
private fun showSoftKeyBoard(context: Context, editBox: EditText?) {
val inputMethodManager = context.getSystemService(FlutterFragmentActivity.INPUT_METHOD_SERVICE) as InputMethodManager
editBox?.requestFocus()
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
}
} }

@ -5,8 +5,8 @@ const ONLY_NUMBERS = "[0-9]";
const ONLY_LETTERS = "[a-zA-Z &'\"]"; const ONLY_LETTERS = "[a-zA-Z &'\"]";
const ONLY_DATE = "[0-9/]"; const ONLY_DATE = "[0-9/]";
const BASE_URL_LIVE_CARE = 'https://livecare.hmg.com/'; const BASE_URL_LIVE_CARE = 'https://livecare.hmg.com/';
// const BASE_URL = 'https://hmgwebservices.com/'; const BASE_URL = 'https://hmgwebservices.com/';
const BASE_URL = 'https://uat.hmgwebservices.com/'; // const BASE_URL = 'https://uat.hmgwebservices.com/';
const PHARMACY_ITEMS_URL = "Services/Lists.svc/REST/GetPharmcyItems_Region_enh"; const PHARMACY_ITEMS_URL = "Services/Lists.svc/REST/GetPharmcyItems_Region_enh";
const PHARMACY_LIST_URL = "Services/Patients.svc/REST/GetPharmcyList"; const PHARMACY_LIST_URL = "Services/Patients.svc/REST/GetPharmcyList";
const PATIENT_PROGRESS_NOTE_URL = "Services/DoctorApplication.svc/REST/GetProgressNoteForInPatient"; const PATIENT_PROGRESS_NOTE_URL = "Services/DoctorApplication.svc/REST/GetProgressNoteForInPatient";

@ -29,12 +29,13 @@ class VideoCallService extends BaseService {
DoctorProfileModel doctorProfile = DoctorProfileModel doctorProfile =
await getDoctorProfile(isGetProfile: true); await getDoctorProfile(isGetProfile: true);
await VideoChannel.openVideoCallScreen( await VideoChannel.openVideoCallScreen(
kToken: startCallRes.openTokenID, // TODO MOSA TEST
kSessionId: startCallRes.openSessionID, // kToken: startCallRes.openTokenID,
kApiKey:'46209962', // kSessionId: startCallRes.openSessionID,
// kToken: "T1==cGFydG5lcl9pZD00NzI0Nzk1NCZzaWc9NGIyZDljOTY3YjFiNWU1YzUzNzFmMjIyNjJmNmEzY2Y5NzZjOTdlYzpzZXNzaW9uX2lkPTFfTVg0ME56STBOemsxTkg1LU1UWXlNekEyTlRRMU9EVXhObjVrVFRoMFlVdFJXaXRYTWpadFZGZHFhSGxZVGpOdE1UVi1mZyZjcmVhdGVfdGltZT0xNjIzMDY1NDk1Jm5vbmNlPTAuMjM2Mjk0NTIwMTkyOTA4OTcmcm9sZT1wdWJsaXNoZXImZXhwaXJlX3RpbWU9MTYyNTY1NzQ5NCZpbml0aWFsX2xheW91dF9jbGFzc19saXN0PQ==", // kApiKey:'46209962',
// kSessionId: "1_MX40NzI0Nzk1NH5-MTYyMzA2NTQ1ODUxNn5kTTh0YUtRWitXMjZtVFdqaHlYTjNtMTV-fg", kToken: "T1==cGFydG5lcl9pZD00NzI0Nzk1NCZzaWc9NGIyZDljOTY3YjFiNWU1YzUzNzFmMjIyNjJmNmEzY2Y5NzZjOTdlYzpzZXNzaW9uX2lkPTFfTVg0ME56STBOemsxTkg1LU1UWXlNekEyTlRRMU9EVXhObjVrVFRoMFlVdFJXaXRYTWpadFZGZHFhSGxZVGpOdE1UVi1mZyZjcmVhdGVfdGltZT0xNjIzMDY1NDk1Jm5vbmNlPTAuMjM2Mjk0NTIwMTkyOTA4OTcmcm9sZT1wdWJsaXNoZXImZXhwaXJlX3RpbWU9MTYyNTY1NzQ5NCZpbml0aWFsX2xheW91dF9jbGFzc19saXN0PQ==",
// kApiKey:'47247954', kSessionId: "1_MX40NzI0Nzk1NH5-MTYyMzA2NTQ1ODUxNn5kTTh0YUtRWitXMjZtVFdqaHlYTjNtMTV-fg",
kApiKey:'47247954',
vcId: patient.vcId, vcId: patient.vcId,
isRecording: isRecording, isRecording: isRecording,
patientName: patient.fullName ?? patientName: patient.fullName ??

@ -338,28 +338,29 @@ class _HomeScreenState extends State<HomeScreen> {
text: text:
"${TranslationBase.of(context).liveCare}\n${TranslationBase.of(context).patients}", "${TranslationBase.of(context).liveCare}\n${TranslationBase.of(context).patients}",
onTap: () { onTap: () {
// PatiantInformtion patient = PatiantInformtion( // TODO MOSA TEST
// patientStatusType: 43, PatiantInformtion patient = PatiantInformtion(
// episodeNo: 0, patientStatusType: 43,
// vcId: 42342, episodeNo: 0,
// fullName: "mosa test", vcId: 42342,
// dateofBirth: "2000-05-01 10:42:35.790004" fullName: "mosa test",
// ); dateofBirth: "2000-05-01 10:42:35.790004"
// Navigator.of(context).pushNamed(PATIENTS_PROFILE, arguments: {
// "patient": patient,
// "patientType": "0",
// "isSearch": false,
// "isInpatient": false,
// "arrivalType": "0",
// "isSearchAndOut": false,
// "isFromLiveCare": true,
// });
Navigator.push(
context,
FadePage(
page: LiveCarePatientScreen(),
),
); );
Navigator.of(context).pushNamed(PATIENTS_PROFILE, arguments: {
"patient": patient,
"patientType": "0",
"isSearch": false,
"isInpatient": false,
"arrivalType": "0",
"isSearchAndOut": false,
"isFromLiveCare": true,
});
// Navigator.push(
// context,
// FadePage(
// page: LiveCarePatientScreen(),
// ),
// );
}, },
)); ));
changeColorIndex(); changeColorIndex();

@ -301,18 +301,19 @@ class _PatientProfileScreenState extends State<PatientProfileScreen> with Single
: TranslationBase.of(context).initiateCall, : TranslationBase.of(context).initiateCall,
disabled: isCallStarted || model.state == ViewState.BusyLocal, disabled: isCallStarted || model.state == ViewState.BusyLocal,
onPressed: () async { onPressed: () async {
// AppPermissionsUtils // TODO MOSA TEST
// .requestVideoCallPermission( AppPermissionsUtils
// context: context, .requestVideoCallPermission(
// onTapGrant: () { context: context,
// locator<VideoCallService>() onTapGrant: () {
// .openVideo( locator<VideoCallService>()
// model.startCallRes, .openVideo(
// patient, model.startCallRes,
// model.startCallRes != null ? model.startCallRes.isRecording : true, callConnected, patient,
// callDisconnected); model.startCallRes != null ? model.startCallRes.isRecording : true, callConnected,
// }); callDisconnected);
if (isCallFinished) { });
/*if (isCallFinished) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -354,7 +355,7 @@ class _PatientProfileScreenState extends State<PatientProfileScreen> with Single
callDisconnected); callDisconnected);
}); });
} }
} }*/
}, },
), ),
), ),

Loading…
Cancel
Save