video stream clean code

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

@ -31,7 +31,7 @@ import pub.devrel.easypermissions.EasyPermissions
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
VideoCallResponseListener, EasyPermissions.PermissionCallbacks {
VideoCallResponseListener {
/* Permission request code to draw over other apps */
private val DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE = 1222
@ -131,8 +131,6 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}
private fun checkFloatingWidgetPermission() {
// requestPermissions()
// 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.
@ -162,27 +160,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler,
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
/*if (requestCode == LAUNCH_VIDEO) {
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) {
if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION_REQUEST_CODE) {
//Check if the permission is granted or not.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
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
class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
class VideoStreamFloatingWidgetService : BaseMovingFloatingWidget(), Session.SessionListener,
PublisherKit.PublisherListener,
SubscriberKit.VideoListener, VideoCallContract.VideoCallView {
@ -41,17 +41,10 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
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_NAME = "Video cAll"
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_MINIMIZE_CALL = "com.hmg.hmgDr.Service.action.minimizeCall"
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
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 thumbnail_container: FrameLayout
private lateinit var activity_clingo_video_call: RelativeLayout
@ -116,7 +99,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private var mCallFirstTime: Date = Date()
private var sessionStatusModel: GetSessionStatusModel? = null
private lateinit var mDetector: GestureDetectorCompat
private var apiKey: String? = null
private var sessionId: String? = null
@ -133,16 +115,10 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private var formattedCallTime: String = "00:00"
private lateinit var notificationData: NotificationVideoModel
private var resume = false
var isFullScreen: Boolean = true
private var isCircle: Boolean = false
lateinit var customAudioDevice: CustomAudioDevice
// notification's layout
private lateinit var mRemoteViews: RemoteViews
private lateinit var mRemoteViewsExpand: RemoteViews
// Notification variables
private var mNotificationManagerCompat: NotificationManagerCompat? = null
private lateinit var notificationCompatBuilder: NotificationCompat.Builder
@ -170,17 +146,8 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
isRecording = sessionStatusModel!!.isRecording
}
//init WindowManager
mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager
getWindowManagerDefaultDisplay()
//Init LayoutInflater
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
addFloatingWidgetView(inflater)
addFloatingWidgetView()
handleDragDialog()
addForegroundService()
}
} 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
}
@ -230,15 +196,12 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
} catch (e: Exception) {
Log.e("onDestroyService", "${e.localizedMessage}.")
}
// disconnectSession()
super.onDestroy()
}
private fun stopService() {
// customAudioDevice.setRendererMute(false)
AudioDeviceManager.getAudioDevice().onPause()
// cmTimer.stop()
mCallTimerRunnable?.let {
mCallTimerHandler?.removeCallbacks(it)
mCallTimerHandler = null
@ -257,36 +220,8 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
}
}
/* Add Floating Widget View to Window Manager */
private fun addFloatingWidgetView(inflater: 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
//Initially the Removing widget view is not visible, so set visibility to GONE
// floatingWidgetView!!.visibility = View.GONE
override fun addFloatingWidgetView() {
super.addFloatingWidgetView()
init(floatingWidgetView!!)
@ -295,33 +230,9 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
}
@SuppressLint("ClickableViewAccessibility", "RestrictedApi")
private fun init(view: View) {
private fun init(view: 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
if (isRecording) {
@ -330,29 +241,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
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)
checkClientConnected()
@ -366,7 +254,8 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
{ miniCircleDoubleTap() })
)
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.setRendererMute(false)
if (AudioDeviceManager.getAudioDevice() == null) {
@ -395,6 +284,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
private fun initUI(view: View) {
videoCallContainer = view.findViewById(R.id.video_call_ll)
floatingViewContainer = videoCallContainer
layoutName = view.findViewById<View>(R.id.layout_name) as RelativeLayout
layoutMini = view.findViewById(R.id.layout_mini)
@ -418,6 +308,28 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
mSwitchCameraBtn = view.findViewById(R.id.btn_switch_camera)
mspeckerBtn = view.findViewById(R.id.btn_specker)
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() {
@ -439,28 +351,10 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
formattedCallTime = DateUtils.differentDateTimeBetweenDateAndNow(mCallFirstTime)
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
if (mNotificationManagerCompat != null) {
val bigTextStyle = setNotificationBigStyle()
notificationData.mSummaryText = formattedCallTime
val bigTextStyle = NotificationUtil.setNotificationBigStyle(notificationData)
notificationCompatBuilder.setStyle(bigTextStyle)
mNotificationManagerCompat?.notify(
ONGOING_NOTIFICATION_ID,
@ -493,7 +387,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
val panelPaddingMedium: Int =
resources.getDimension(R.dimen.padding_space_medium).toInt()
val temp = getStatusBarHeight() / 2
val temp = ViewsUtil.getStatusBarHeight(applicationContext) / 2
val screenWidth: Float
val screenHeight: Float
@ -654,6 +548,13 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
handleVideoViewHeight()
}
@SuppressLint("ClickableViewAccessibility")
private fun handleDragDialog() {
getWindowManagerDefaultDisplay()
videoCallContainer.setOnTouchListener(dragListener)
mSubscriberViewContainer.setOnTouchListener(dragListener)
}
/***
* Click Listener
@ -706,14 +607,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
mPublisher!!.publishVideo = !isCameraClicked
val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled
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) {
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) {
@ -1050,7 +940,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
}
}
fun onCallChangeCallStatusSuccessful() {
private fun onCallChangeCallStatusSuccessful() {
val returnIntent = Intent()
returnIntent.putExtra("CallEnd", sessionStatusModel)
videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED, returnIntent)
@ -1062,22 +952,9 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
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() {
mNotificationManagerCompat = NotificationManagerCompat.from(applicationContext)
val areNotificationsEnabled = mNotificationManagerCompat!!.areNotificationsEnabled()
@ -1088,23 +965,12 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
Toast.LENGTH_SHORT
).show()
// Links to this app's notification settings
openNotificationSettingsForApp()
NotificationUtil.openNotificationSettingsForApp(applicationContext)
return
}
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() {
notificationData =
NotificationVideoModel(
@ -1120,7 +986,7 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
NotificationUtil.createNotificationChannel(this, notificationData)
// 2. Build the BIG_TEXT_STYLE.
val bigTextStyle = setNotificationBigStyle()
val bigTextStyle = NotificationUtil.setNotificationBigStyle(notificationData)
// 3. Set up main Intent for notification.
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
// BIG_TEXT_STYLE sets title and content for API 16 (4.1 and after).
.setStyle(bigTextStyle)
@ -1244,217 +1058,6 @@ class VideoStreamFloatingWidgetService : Service(), Session.SessionListener,
mNotificationManagerCompat!!.notify(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.NotificationManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import androidx.core.app.NotificationCompat
import com.hmg.hmgDr.model.NotificationDataModel
import com.hmg.hmgDr.model.NotificationVideoModel
object NotificationUtil {
@ -45,4 +48,30 @@ object NotificationUtil {
}
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.widget.EditText
import io.flutter.embedding.android.FlutterFragmentActivity
import kotlin.math.ceil
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
* @return the Screen height in DP

@ -43,16 +43,6 @@
android:textStyle="bold"
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>
</RelativeLayout>

Loading…
Cancel
Save