video stream clean code

merge-requests/779/head
mosazaid 5 years ago
parent 9f1631ba4c
commit a020c9865b

@ -31,7 +31,7 @@ import pub.devrel.easypermissions.EasyPermissions
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler, class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
VideoCallResponseListener, EasyPermissions.PermissionCallbacks { VideoCallResponseListener {
/* Permission request code to draw over other apps */ /* Permission request code to draw over other apps */
private val DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE = 1222 private val DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE = 1222
@ -131,8 +131,6 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
} }
private fun checkFloatingWidgetPermission() { private fun checkFloatingWidgetPermission() {
// requestPermissions()
// Check if the application has draw over other apps permission or not? // 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 // This permission is by default available for API<23. But for API > 23
// you have to ask for the permission in runtime. // you have to ask for the permission in runtime.
@ -162,27 +160,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
/*if (requestCode == LAUNCH_VIDEO) { if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
val result : SessionStatusModel? = data?.getParcelableExtra("sessionStatusNotRespond")
val callResponse : HashMap<String, String> = HashMap()
val sessionStatus : HashMap<String, String> = HashMap()
val gson = GsonBuilder().serializeNulls().create()
callResponse["callResponse"] = "CallNotRespond"
val jsonRes = gson.toJson(result)
callResponse["sessionStatus"] = jsonRes
this.result?.success(callResponse)
}
if (resultCode == Activity.RESULT_CANCELED) {
val callResponse : HashMap<String, String> = HashMap()
callResponse["callResponse"] = "CallEnd"
result?.success(callResponse)
}
} else*/ if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) {
//Check if the permission is granted or not. //Check if the permission is granted or not.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.canDrawOverlays(this)) { if (Settings.canDrawOverlays(this)) {
@ -303,67 +281,4 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
} }
} }
@AfterPermissionGranted(RC_READ_WRITE)
private fun requestPermissions() {
val perms = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
var havePermission = false
for (requiredPermission: String in perms) {
val checkVal: Int = checkCallingOrSelfPermission(requiredPermission)
if (checkVal == PackageManager.PERMISSION_GRANTED) {
havePermission = true
}
}
if (!havePermission) {
EasyPermissions.requestPermissions(
this,
getString(R.string.remaining_ar),
RC_READ_WRITE,
*perms
)
}
/* if (EasyPermissions.hasPermissions(this, *perms)) {
} else {
EasyPermissions.requestPermissions(
this,
getString(R.string.remaining_ar),
RC_READ_WRITE,
*perms
)
}*/
}
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>?) {
}
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
if (EasyPermissions.somePermissionPermanentlyDenied(this@MainActivity, 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()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
companion object {
private const val RC_READ_WRITE = 1
private const val RC_SETTINGS_SCREEN_PERM = 123
}
} }

@ -0,0 +1,234 @@
package com.hmg.hmgDr.Service
import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Point
import android.os.Build
import android.os.CountDownTimer
import android.util.Log
import android.view.*
import androidx.core.view.GestureDetectorCompat
import com.hmg.hmgDr.R
import com.hmg.hmgDr.util.ViewsUtil
abstract class BaseMovingFloatingWidget : Service() {
val szWindow = Point()
lateinit var windowManagerParams: WindowManager.LayoutParams
var mWindowManager: WindowManager? = null
var floatingWidgetView: View? = null
lateinit var floatingViewContainer: View
lateinit var mDetector: GestureDetectorCompat
private var xInitCord = 0
private var yInitCord: Int = 0
private var xInitMargin: Int = 0
private var yInitMargin: Int = 0
/* Add Floating Widget View to Window Manager */
open fun addFloatingWidgetView() {
mWindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
//Init LayoutInflater
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
//Inflate the removing view layout we created
floatingWidgetView = inflater.inflate(R.layout.activity_video_call, null)
//Add the view to the window.
windowManagerParams =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
} else {
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
}
//Specify the view position
windowManagerParams.gravity = Gravity.TOP or Gravity.START
}
@SuppressLint("ClickableViewAccessibility")
val dragListener: View.OnTouchListener = View.OnTouchListener { _, event ->
mDetector.onTouchEvent(event)
//Get Floating widget view params
val layoutParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
//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 -> {
xInitCord = x_cord
yInitCord = y_cord
//remember the initial position.
xInitMargin = layoutParams.x
yInitMargin = layoutParams.y
}
MotionEvent.ACTION_UP -> {
//Get the difference between initial coordinate and current coordinate
val x_diff: Int = x_cord - xInitCord
val y_diff: Int = y_cord - yInitCord
y_cord_Destination = yInitMargin + y_diff
val barHeight: Int = ViewsUtil.getStatusBarHeight(applicationContext)
if (y_cord_Destination < 0) {
y_cord_Destination = 0
// y_cord_Destination =
// -(szWindow.y - (videoCallContainer.height /*+ barHeight*/))
// y_cord_Destination = -(szWindow.y / 2)
} else if (y_cord_Destination + (floatingViewContainer.height + barHeight) > szWindow.y) {
y_cord_Destination = szWindow.y - (floatingViewContainer.height + barHeight)
// y_cord_Destination = (szWindow.y / 2)
}
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 - xInitCord
val y_diff_move: Int = y_cord - yInitCord
x_cord_Destination = xInitMargin + x_diff_move
y_cord_Destination = yInitMargin + y_diff_move
layoutParams.x = x_cord_Destination
layoutParams.y = y_cord_Destination
//Update the layout with new X & Y coordinate
mWindowManager?.updateViewLayout(floatingWidgetView, layoutParams)
}
}
true
}
/**
* OnTouch actions
*/
class MyGestureListener(
val onTabCall: () -> Unit,
val miniCircleDoubleTap: () -> Unit
) : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
// onTabCall()
return true
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
miniCircleDoubleTap()
return super.onDoubleTap(e)
}
}
/* Reset position of Floating Widget view on dragging */
fun resetPosition(x_cord_now: Int) {
if (x_cord_now <= szWindow.x / 2) {
moveToLeft(x_cord_now)
} else {
moveToRight(x_cord_now)
}
}
/* Method to move the Floating widget view to Left */
private fun moveToLeft(current_x_cord: Int) {
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
mParams.x =
(szWindow.x - current_x_cord * current_x_cord - floatingViewContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
val x = szWindow.x - current_x_cord
object : CountDownTimer(500, 5) {
//get params of Floating Widget view
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
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 - floatingViewContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = -(szWindow.x - floatingViewContainer.width)
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
}.start()
}
/* Method to move the Floating widget view to Right */
private fun moveToRight(current_x_cord: Int) {
object : CountDownTimer(500, 5) {
//get params of Floating Widget view
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
override fun onTick(t: Long) {
val step = (500 - t) / 5
mParams.x =
(szWindow.x + current_x_cord * current_x_cord * step - floatingViewContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = szWindow.x - floatingViewContainer.width
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
}
}.start()
}
/***
* Utils
*/
fun getWindowManagerDefaultDisplay() {
val w = mWindowManager!!.defaultDisplay.width
val h = mWindowManager!!.defaultDisplay.height
szWindow[w] = h
}
}

@ -32,7 +32,7 @@ import java.util.*
import kotlin.math.ceil import kotlin.math.ceil
class VideoStreamFloatingWidgetService : Service(), Session.SessionListener, class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.SessionListener,
PublisherKit.PublisherListener, PublisherKit.PublisherListener,
SubscriberKit.VideoListener, VideoCallContract.VideoCallView { SubscriberKit.VideoListener, VideoCallContract.VideoCallView {
@ -41,17 +41,10 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private val TAG = VideoStreamFloatingWidgetService::class.java.simpleName private val TAG = VideoStreamFloatingWidgetService::class.java.simpleName
private const val RC_SETTINGS_SCREEN_PERM = 123
private const val RC_VIDEO_APP_PERM = 124
const val CHANNEL_DEFAULT_IMPORTANCE = "Video_stream_channel" const val CHANNEL_DEFAULT_IMPORTANCE = "Video_stream_channel"
const val CHANNEL_DEFAULT_NAME = "Video cAll" const val CHANNEL_DEFAULT_NAME = "Video cAll"
const val ONGOING_NOTIFICATION_ID = 1 const val ONGOING_NOTIFICATION_ID = 1
private const val TEST_DURATION = 20 //test quality duration in seconds
private const val TIME_WINDOW = 3 //3 seconds
private const val TIME_VIDEO_TEST = 15 //time interval to check the video quality in seconds
const val ACTION_START_CALL = "com.hmg.hmgDr.Service.action.startCall" const val ACTION_START_CALL = "com.hmg.hmgDr.Service.action.startCall"
const val ACTION_MINIMIZE_CALL = "com.hmg.hmgDr.Service.action.minimizeCall" const val ACTION_MINIMIZE_CALL = "com.hmg.hmgDr.Service.action.minimizeCall"
const val ACTION_END_CALL = "com.hmg.hmgDr.Service.action.endCall" const val ACTION_END_CALL = "com.hmg.hmgDr.Service.action.endCall"
@ -67,16 +60,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private lateinit var videoCallPresenter: VideoCallContract.VideoCallPresenter private lateinit var videoCallPresenter: VideoCallContract.VideoCallPresenter
var videoCallResponseListener: VideoCallResponseListener? = null var videoCallResponseListener: VideoCallResponseListener? = null
private lateinit var windowManagerParams: WindowManager.LayoutParams
private var mWindowManager: WindowManager? = null
private val szWindow = Point()
private var floatingWidgetView: View? = null
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 lateinit var recordContainer: FrameLayout private lateinit var recordContainer: FrameLayout
private lateinit var thumbnail_container: FrameLayout private lateinit var thumbnail_container: FrameLayout
private lateinit var activity_clingo_video_call: RelativeLayout private lateinit var activity_clingo_video_call: RelativeLayout
@ -116,7 +99,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private var mCallFirstTime: Date = Date() private var mCallFirstTime: Date = Date()
private var sessionStatusModel: GetSessionStatusModel? = null private var sessionStatusModel: GetSessionStatusModel? = null
private lateinit var mDetector: GestureDetectorCompat
private var apiKey: String? = null private var apiKey: String? = null
private var sessionId: String? = null private var sessionId: String? = null
@ -133,16 +115,10 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private var formattedCallTime: String = "00:00" private var formattedCallTime: String = "00:00"
private lateinit var notificationData: NotificationVideoModel private lateinit var notificationData: NotificationVideoModel
private var resume = false
var isFullScreen: Boolean = true var isFullScreen: Boolean = true
private var isCircle: Boolean = false private var isCircle: Boolean = false
lateinit var customAudioDevice: CustomAudioDevice lateinit var customAudioDevice: CustomAudioDevice
// notification's layout
private lateinit var mRemoteViews: RemoteViews
private lateinit var mRemoteViewsExpand: RemoteViews
// Notification variables // Notification variables
private var mNotificationManagerCompat: NotificationManagerCompat? = null private var mNotificationManagerCompat: NotificationManagerCompat? = null
private lateinit var notificationCompatBuilder: NotificationCompat.Builder private lateinit var notificationCompatBuilder: NotificationCompat.Builder
@ -170,17 +146,8 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
isRecording = sessionStatusModel!!.isRecording isRecording = sessionStatusModel!!.isRecording
} }
//init WindowManager addFloatingWidgetView()
mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager
getWindowManagerDefaultDisplay()
//Init LayoutInflater
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
addFloatingWidgetView(inflater)
handleDragDialog() handleDragDialog()
addForegroundService() addForegroundService()
} }
} else if (action == ACTION_END_CALL) { } else if (action == ACTION_END_CALL) {
@ -211,7 +178,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
} }
} }
// Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show()
return START_STICKY return START_STICKY
} }
@ -230,15 +196,12 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
} catch (e: Exception) { } catch (e: Exception) {
Log.e("onDestroyService", "${e.localizedMessage}.") Log.e("onDestroyService", "${e.localizedMessage}.")
} }
// disconnectSession()
super.onDestroy() super.onDestroy()
} }
private fun stopService() { private fun stopService() {
// customAudioDevice.setRendererMute(false)
AudioDeviceManager.getAudioDevice().onPause() AudioDeviceManager.getAudioDevice().onPause()
// cmTimer.stop()
mCallTimerRunnable?.let { mCallTimerRunnable?.let {
mCallTimerHandler?.removeCallbacks(it) mCallTimerHandler?.removeCallbacks(it)
mCallTimerHandler = null mCallTimerHandler = null
@ -257,36 +220,8 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
} }
} }
/* Add Floating Widget View to Window Manager */ override fun addFloatingWidgetView() {
private fun addFloatingWidgetView(inflater: LayoutInflater) { super.addFloatingWidgetView()
//Inflate the removing view layout we created
floatingWidgetView = inflater.inflate(R.layout.activity_video_call, null)
//Add the view to the window.
windowManagerParams =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
} else {
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
}
//Specify the view position
windowManagerParams.gravity = Gravity.TOP or Gravity.START
//Initially the Removing widget view is not visible, so set visibility to GONE
// floatingWidgetView!!.visibility = View.GONE
init(floatingWidgetView!!) init(floatingWidgetView!!)
@ -295,33 +230,9 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
} }
@SuppressLint("ClickableViewAccessibility", "RestrictedApi") @SuppressLint("ClickableViewAccessibility", "RestrictedApi")
private fun init(view: View) { private fun init(view: View) {
initUI(view) initUI(view)
mCallBtn.setOnClickListener {
onCallClicked()
}
btnMinimize.setOnClickListener {
onMinimizedClicked()
}
mCameraBtn.setOnClickListener {
onCameraClicked(it)
}
mSwitchCameraBtn.setOnClickListener {
onSwitchCameraClicked(it)
}
mspeckerBtn.setOnClickListener {
onSpeckerClicked(it)
}
mMicBtn.setOnClickListener {
onMicClicked(it)
}
icMini.setOnClickListener {
onMiniCircleClicked()
}
// hiddenButtons()
patientName.text = sessionStatusModel!!.patientName patientName.text = sessionStatusModel!!.patientName
if (isRecording) { if (isRecording) {
@ -330,29 +241,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
recordContainer.visibility = View.GONE recordContainer.visibility = View.GONE
} }
/*
cmTimer.format = "mm:ss"
cmTimer.onChronometerTickListener =
Chronometer.OnChronometerTickListener { arg0: Chronometer ->
// val f: NumberFormat = DecimalFormat("00")
// f.format(minutes)
val minutes: Long
val seconds: Long
if (!resume) {
minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60
seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60
elapsedTime = SystemClock.elapsedRealtime()
} else {
minutes = (elapsedTime - cmTimer.base) / 1000 / 60
seconds = (elapsedTime - cmTimer.base) / 1000 % 60
elapsedTime += 1000
}
val format = "%1$02d:%2$02d" // two digits
formattedCallTime = String.format(format, minutes, seconds)
arg0.text = formattedCallTime
}
*/
videoCallPresenter = VideoCallPresenterImpl(this, baseUrl) videoCallPresenter = VideoCallPresenterImpl(this, baseUrl)
checkClientConnected() checkClientConnected()
@ -366,7 +254,8 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
{ miniCircleDoubleTap() }) { miniCircleDoubleTap() })
) )
try { try {
// Add a custom audio device before session initialization // Add a custom audio device before session initialization,
// so when the service is destroyed it will not be errors that receivers is still in memory
customAudioDevice = CustomAudioDevice(this) customAudioDevice = CustomAudioDevice(this)
customAudioDevice.setRendererMute(false) customAudioDevice.setRendererMute(false)
if (AudioDeviceManager.getAudioDevice() == null) { if (AudioDeviceManager.getAudioDevice() == null) {
@ -395,6 +284,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private fun initUI(view: View) { private fun initUI(view: View) {
videoCallContainer = view.findViewById(R.id.video_call_ll) videoCallContainer = view.findViewById(R.id.video_call_ll)
floatingViewContainer = videoCallContainer
layoutName = view.findViewById<View>(R.id.layout_name) as RelativeLayout layoutName = view.findViewById<View>(R.id.layout_name) as RelativeLayout
layoutMini = view.findViewById(R.id.layout_mini) layoutMini = view.findViewById(R.id.layout_mini)
@ -418,6 +308,28 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
mSwitchCameraBtn = view.findViewById(R.id.btn_switch_camera) mSwitchCameraBtn = view.findViewById(R.id.btn_switch_camera)
mspeckerBtn = view.findViewById(R.id.btn_specker) mspeckerBtn = view.findViewById(R.id.btn_specker)
mMicBtn = view.findViewById(R.id.btn_mic) mMicBtn = view.findViewById(R.id.btn_mic)
mCallBtn.setOnClickListener {
onCallClicked()
}
btnMinimize.setOnClickListener {
onMinimizedClicked()
}
mCameraBtn.setOnClickListener {
onCameraClicked(it)
}
mSwitchCameraBtn.setOnClickListener {
onSwitchCameraClicked(it)
}
mspeckerBtn.setOnClickListener {
onSpeckerClicked(it)
}
mMicBtn.setOnClickListener {
onMicClicked(it)
}
icMini.setOnClickListener {
onMiniCircleClicked()
}
} }
private fun checkClientConnected() { private fun checkClientConnected() {
@ -439,28 +351,10 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
formattedCallTime = DateUtils.differentDateTimeBetweenDateAndNow(mCallFirstTime) formattedCallTime = DateUtils.differentDateTimeBetweenDateAndNow(mCallFirstTime)
tvTimer.text = formattedCallTime tvTimer.text = formattedCallTime
/*
// comment it because I deleted remoteView
try {
notificationCompatBuilder.contentView.setChronometer(
R.id.notify_timer,
cmTimer.base,
null,
true
)
notificationCompatBuilder.bigContentView.setChronometer(
R.id.notify_timer,
cmTimer.base,
null,
true
)
} catch (e: Exception) {
print(e)
}*/
// for change notification timer // for change notification timer
if (mNotificationManagerCompat != null) { if (mNotificationManagerCompat != null) {
val bigTextStyle = setNotificationBigStyle() notificationData.mSummaryText = formattedCallTime
val bigTextStyle = NotificationUtil.setNotificationBigStyle(notificationData)
notificationCompatBuilder.setStyle(bigTextStyle) notificationCompatBuilder.setStyle(bigTextStyle)
mNotificationManagerCompat?.notify( mNotificationManagerCompat?.notify(
ONGOING_NOTIFICATION_ID, ONGOING_NOTIFICATION_ID,
@ -493,7 +387,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
val panelPaddingMedium: Int = val panelPaddingMedium: Int =
resources.getDimension(R.dimen.padding_space_medium).toInt() resources.getDimension(R.dimen.padding_space_medium).toInt()
val temp = getStatusBarHeight() / 2 val temp = ViewsUtil.getStatusBarHeight(applicationContext) / 2
val screenWidth: Float val screenWidth: Float
val screenHeight: Float val screenHeight: Float
@ -654,6 +548,13 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
handleVideoViewHeight() handleVideoViewHeight()
} }
@SuppressLint("ClickableViewAccessibility")
private fun handleDragDialog() {
getWindowManagerDefaultDisplay()
videoCallContainer.setOnTouchListener(dragListener)
mSubscriberViewContainer.setOnTouchListener(dragListener)
}
/*** /***
* Click Listener * Click Listener
@ -706,14 +607,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
mPublisher!!.publishVideo = !isCameraClicked mPublisher!!.publishVideo = !isCameraClicked
val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled
mCameraBtn.setImageResource(res) mCameraBtn.setImageResource(res)
// if (!isCameraClicked) {
// videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
// mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
// } else {
// videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
// mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.remoteBackground))
// }
} }
} }
@ -855,9 +748,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
override fun onError(session: Session, opentokError: OpentokError) { override fun onError(session: Session, opentokError: OpentokError) {
Log.d(TAG, "onError: Error (" + opentokError.message + ") in session " + session.sessionId) Log.d(TAG, "onError: Error (" + opentokError.message + ") in session " + session.sessionId)
// videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in session ")
// dialog?.dismiss()
} }
override fun onStreamReceived(session: Session, stream: Stream) { override fun onStreamReceived(session: Session, stream: Stream) {
@ -1050,7 +940,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
} }
} }
fun onCallChangeCallStatusSuccessful() { private fun onCallChangeCallStatusSuccessful() {
val returnIntent = Intent() val returnIntent = Intent()
returnIntent.putExtra("CallEnd", sessionStatusModel) returnIntent.putExtra("CallEnd", sessionStatusModel)
videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED, returnIntent) videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED, returnIntent)
@ -1062,22 +952,9 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
override fun onFailure() {} override fun onFailure() {}
/*** /***
* Utils * Notification methods
*/ */
private fun getWindowManagerDefaultDisplay() {
val w = mWindowManager!!.defaultDisplay.width
val h = mWindowManager!!.defaultDisplay.height
szWindow[w] = h
}
/* return status bar height on basis of device display metrics */
private fun getStatusBarHeight(): Int {
return ceil(
(25 * applicationContext.resources.displayMetrics.density).toDouble()
).toInt()
}
private fun addForegroundService() { private fun addForegroundService() {
mNotificationManagerCompat = NotificationManagerCompat.from(applicationContext) mNotificationManagerCompat = NotificationManagerCompat.from(applicationContext)
val areNotificationsEnabled = mNotificationManagerCompat!!.areNotificationsEnabled() val areNotificationsEnabled = mNotificationManagerCompat!!.areNotificationsEnabled()
@ -1088,23 +965,12 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
// Links to this app's notification settings // Links to this app's notification settings
openNotificationSettingsForApp() NotificationUtil.openNotificationSettingsForApp(applicationContext)
return return
} }
generateBigTextStyleNotification() generateBigTextStyleNotification()
} }
private fun setNotificationBigStyle(): NotificationCompat.BigTextStyle {
notificationData.mSummaryText = formattedCallTime
return NotificationCompat.BigTextStyle() // Overrides ContentText in the big form of the template.
.bigText(notificationData.mBigText) // Overrides ContentTitle in the big form of the template.
.setBigContentTitle(notificationData.mBigContentTitle) // Summary line after the detail section in the big form of the template.
// Note: To improve readability, don't overload the user with info. If Summary Text
// doesn't add critical information, you should skip it.
.setSummaryText(notificationData.mSummaryText)
}
private fun generateBigTextStyleNotification() { private fun generateBigTextStyleNotification() {
notificationData = notificationData =
NotificationVideoModel( NotificationVideoModel(
@ -1120,7 +986,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
NotificationUtil.createNotificationChannel(this, notificationData) NotificationUtil.createNotificationChannel(this, notificationData)
// 2. Build the BIG_TEXT_STYLE. // 2. Build the BIG_TEXT_STYLE.
val bigTextStyle = setNotificationBigStyle() val bigTextStyle = NotificationUtil.setNotificationBigStyle(notificationData)
// 3. Set up main Intent for notification. // 3. Set up main Intent for notification.
val pendingIntent: PendingIntent = val pendingIntent: PendingIntent =
@ -1154,58 +1020,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
) )
} }
/*
mRemoteViews = RemoteViews(packageName, R.layout.notifi_video_view)
mRemoteViewsExpand = RemoteViews(packageName, R.layout.notifi_video_view_expand)
val changeCollapsedIntent: PendingIntent =
Intent(this, VideoStreamFloatingWidgetService::class.java).apply {
action = ACTION_CHANGE_EXPANDED_COLLAPSED
val extras = Bundle()
extras.putBoolean(NOTIFICATION_IS_EXPANDED, false)
putExtras(extras)
}
.let { notificationIntent ->
PendingIntent.getService(this, 0, notificationIntent, 0)
}
val changeExpandedIntent: PendingIntent =
Intent(this, VideoStreamFloatingWidgetService::class.java).apply {
action = ACTION_CHANGE_EXPANDED_COLLAPSED
val extras = Bundle()
extras.putBoolean(NOTIFICATION_IS_EXPANDED, true)
putExtras(extras)
}
.let { notificationIntent ->
PendingIntent.getService(this, 0, notificationIntent, 0)
}
mRemoteViews.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher)
// notification's title
mRemoteViews.setTextViewText(R.id.notify_title, notificationData.mContentTitle)
// notification's content
mRemoteViews.setTextViewText(R.id.notify_content, notificationData.mContentText)
mRemoteViews.setOnClickPendingIntent(R.id.iv_Arrow, changeCollapsedIntent)
mRemoteViews.setChronometer(
R.id.notify_timer,
SystemClock.elapsedRealtime(),
null,
false
)
mRemoteViewsExpand.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher)
mRemoteViewsExpand.setTextViewText(R.id.notify_title, notificationData.mContentTitle)
mRemoteViewsExpand.setTextViewText(R.id.notify_content, notificationData.mContentText)
mRemoteViewsExpand.setOnClickPendingIntent(R.id.btn_end, endCallPendingIntent)
mRemoteViewsExpand.setOnClickPendingIntent(R.id.iv_Arrow, changeExpandedIntent)
mRemoteViewsExpand.setChronometer(
R.id.notify_timer,
SystemClock.elapsedRealtime(),
null,
false
)
*/
notificationCompatBuilder notificationCompatBuilder
// BIG_TEXT_STYLE sets title and content for API 16 (4.1 and after). // BIG_TEXT_STYLE sets title and content for API 16 (4.1 and after).
.setStyle(bigTextStyle) .setStyle(bigTextStyle)
@ -1244,217 +1058,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
mNotificationManagerCompat!!.notify(ONGOING_NOTIFICATION_ID, notification) mNotificationManagerCompat!!.notify(ONGOING_NOTIFICATION_ID, notification)
startForeground(ONGOING_NOTIFICATION_ID, notification) startForeground(ONGOING_NOTIFICATION_ID, notification)
/*val notification: Notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder(this, CHANNEL_DEFAULT_IMPORTANCE)
.setContentTitle("")
.setContentText("")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build()
} else {
Notification.Builder(this)
.setContentTitle("")
.setContentText("")
.setSmallIcon(R.mipmap.ic_launcher)
.setOngoing(true)
.setContentIntent(pendingIntent)
.build()
}
// Notification ID cannot be 0.
*/
}
/**
* IMPORTANT NOTE: You should not do this action unless the user takes an action to see your
* Notifications like this sample demonstrates. Spamming users to re-enable your notifications
* is a bad idea.
*/
private fun openNotificationSettingsForApp() {
// Links to this app's notification settings.
val intent = Intent()
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
intent.putExtra("app_package", packageName)
intent.putExtra("app_uid", applicationInfo.uid)
// for Android 8 and above
intent.putExtra("android.provider.extra.APP_PACKAGE", packageName)
startActivity(intent)
}
/**
* OnTouch actions
*/
private class MyGestureListener(
val onTabCall: () -> Unit,
val miniCircleDoubleTap: () -> Unit
) : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
// onTabCall()
return true
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
miniCircleDoubleTap()
return super.onDoubleTap(e)
}
}
@SuppressLint("ClickableViewAccessibility")
private fun handleDragDialog() {
mWindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
getWindowManagerDefaultDisplay()
videoCallContainer.setOnTouchListener(dragListener)
mSubscriberViewContainer.setOnTouchListener(dragListener)
}
@SuppressLint("ClickableViewAccessibility")
private val dragListener: View.OnTouchListener = View.OnTouchListener { _, event ->
mDetector.onTouchEvent(event)
//Get Floating widget view params
val layoutParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
//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*/))
// y_cord_Destination = -(szWindow.y / 2)
} else if (y_cord_Destination + (videoCallContainer.height + barHeight) > szWindow.y) {
y_cord_Destination = szWindow.y - (videoCallContainer.height + barHeight)
// y_cord_Destination = (szWindow.y / 2)
}
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
//Update the layout with new X & Y coordinate
mWindowManager?.updateViewLayout(floatingWidgetView, layoutParams)
}
}
true
}
/* Reset position of Floating Widget view on dragging */
private fun resetPosition(x_cord_now: Int) {
if (x_cord_now <= szWindow.x / 2) {
moveToLeft(x_cord_now)
} else {
moveToRight(x_cord_now)
}
}
/* Method to move the Floating widget view to Left */
private fun moveToLeft(current_x_cord: Int) {
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
mParams.x =
(szWindow.x - current_x_cord * current_x_cord - videoCallContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
val x = szWindow.x - current_x_cord
object : CountDownTimer(500, 5) {
//get params of Floating Widget view
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
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()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = -(szWindow.x - videoCallContainer.width)
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
}.start()
} }
/* 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
val mParams: WindowManager.LayoutParams =
floatingWidgetView!!.layoutParams as WindowManager.LayoutParams
override fun onTick(t: Long) {
val step = (500 - t) / 5
mParams.x =
(szWindow.x + current_x_cord * current_x_cord * step - videoCallContainer.width).toInt()
try {
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
} catch (e: Exception) {
Log.e("windowManagerUpdate", "${e.localizedMessage}.")
}
}
override fun onFinish() {
mParams.x = szWindow.x - videoCallContainer.width
mWindowManager?.updateViewLayout(floatingWidgetView, mParams)
}
}.start()
}
} }

@ -3,9 +3,12 @@ package com.hmg.hmgDr.util
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
import androidx.core.app.NotificationCompat
import com.hmg.hmgDr.model.NotificationDataModel import com.hmg.hmgDr.model.NotificationDataModel
import com.hmg.hmgDr.model.NotificationVideoModel
object NotificationUtil { object NotificationUtil {
@ -45,4 +48,30 @@ object NotificationUtil {
} }
return channelId return channelId
} }
fun setNotificationBigStyle(notificationData : NotificationVideoModel): NotificationCompat.BigTextStyle {
return NotificationCompat.BigTextStyle() // Overrides ContentText in the big form of the template.
.bigText(notificationData.mBigText) // Overrides ContentTitle in the big form of the template.
.setBigContentTitle(notificationData.mBigContentTitle) // Summary line after the detail section in the big form of the template.
// Note: To improve readability, don't overload the user with info. If Summary Text
// doesn't add critical information, you should skip it.
.setSummaryText(notificationData.mSummaryText)
}
/**
* IMPORTANT NOTE: You should not do this action unless the user takes an action to see your
* Notifications like this sample demonstrates. Spamming users to re-enable your notifications
* is a bad idea.
*/
fun openNotificationSettingsForApp(context: Context) {
// Links to this app's notification settings.
val intent = Intent()
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
intent.putExtra("app_package", context.packageName)
intent.putExtra("app_uid", context.applicationInfo.uid)
// for Android 8 and above
intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)
context.startActivity(intent)
}
} }

@ -5,9 +5,17 @@ import android.util.DisplayMetrics
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.EditText import android.widget.EditText
import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.android.FlutterFragmentActivity
import kotlin.math.ceil
object ViewsUtil { object ViewsUtil {
/* return status bar height on basis of device display metrics */
fun getStatusBarHeight(context: Context): Int {
return ceil(
(25 * context.resources.displayMetrics.density).toDouble()
).toInt()
}
/** /**
* @param context * @param context
* @return the Screen height in DP * @return the Screen height in DP

@ -43,16 +43,6 @@
android:textStyle="bold" android:textStyle="bold"
android:text="00:00" /> android:text="00:00" />
<!-- <Chronometer-->
<!-- android:id="@+id/cmTimer"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:padding="4dp"-->
<!-- android:textColor="@color/white"-->
<!-- android:textSize="16sp"-->
<!-- android:textStyle="bold"-->
<!-- tools:text="25:45" />-->
</FrameLayout> </FrameLayout>
</RelativeLayout> </RelativeLayout>

Loading…
Cancel
Save