diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt index b21d7bd5..f1c2c602 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/MainActivity.kt @@ -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 = HashMap() - - val sessionStatus : HashMap = 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 = 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?) { - - } - - override fun onPermissionsDenied(requestCode: Int, perms: MutableList) { - 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, - 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 - } } diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/Service/BaseMovingFloatingWidget.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/Service/BaseMovingFloatingWidget.kt new file mode 100644 index 00000000..220d2fc4 --- /dev/null +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/Service/BaseMovingFloatingWidget.kt @@ -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 + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/Service/VideoStreamFloatingWidgetService.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/Service/VideoStreamFloatingWidgetService.kt index 6cf767e0..fb152322 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/Service/VideoStreamFloatingWidgetService.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/Service/VideoStreamFloatingWidgetService.kt @@ -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(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() - } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/util/NotificationUtil.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/util/NotificationUtil.kt index 47da457e..29a2b564 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/util/NotificationUtil.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/util/NotificationUtil.kt @@ -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) + } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/util/viewsUtil.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/util/viewsUtil.kt index 1a6dee64..f7912843 100644 --- a/android/app/src/main/kotlin/com/hmg/hmgDr/util/viewsUtil.kt +++ b/android/app/src/main/kotlin/com/hmg/hmgDr/util/viewsUtil.kt @@ -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 diff --git a/android/app/src/main/res/layout/activity_video_call.xml b/android/app/src/main/res/layout/activity_video_call.xml index 8f49c82b..78d9859e 100644 --- a/android/app/src/main/res/layout/activity_video_call.xml +++ b/android/app/src/main/res/layout/activity_video_call.xml @@ -43,16 +43,6 @@ android:textStyle="bold" android:text="00:00" /> - - - - - - - - - -