package com.yidianling.muse.service import android.app.NotificationChannel import android.app.NotificationManager import android.app.Service import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.graphics.PixelFormat import android.media.MediaPlayer import android.os.Binder import android.os.Build import android.os.IBinder import android.util.DisplayMetrics import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.WindowManager import android.widget.ImageView import android.widget.TextView import androidx.core.app.NotificationCompat import com.bumptech.glide.Glide import com.ydl.ydlcommon.data.http.ThrowableConsumer import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils import com.yidianling.home.http.MuseHttp import com.yidianling.muse.R import com.yidianling.muse.activity.PlayMeditationActivity import com.yidianling.muse.bean.MeditationPlayModuleBean import com.yidianling.muse.constants.MuseBIConstants import com.yidianling.muse.event.MeditationFloatEvent import com.yidianling.muse.helper.FloatViewTouchListener import com.yidianling.muse.helper.MediaPlayerManager import com.yidianling.muse.utils.MediaPlayerTimeUtil import de.greenrobot.event.EventBus import io.feeeei.circleseekbar.CircleSeekBar import io.reactivex.Observable import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.activity_play_meditation.* import kotlinx.android.synthetic.main.player_control_view.* import java.util.* import java.util.concurrent.TimeUnit import kotlin.math.roundToInt class MeditationWindowService : Service() { private lateinit var mWindowManager: WindowManager private var floatRootView: View? = null private var ivClose: ImageView? = null private var ivCover: ImageView? = null private var tvTitle: TextView? = null private var ivProgress: CircleSeekBar? = null private var ivPlayOrPause: ImageView? = null private var mMediaPlayer: MediaPlayer? = null private var mTimer = Timer() private var mCurrentMeditation: MeditationPlayModuleBean.MeditationDetail? = null private var mMeditations = mutableListOf<MeditationPlayModuleBean.MeditationDetail>() private var windowIsShow = false private var mDisposable: Disposable? = null private var mObservable: Observable<Long>? = null private var mObserver: Observer<Long>? = null private var currentMediaId:Long? = null inner class MeditationBinder : Binder() { val service: MeditationWindowService get() = this@MeditationWindowService } override fun onCreate() { super.onCreate() EventBus.getDefault().register(this) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val channel = NotificationChannel("壹点灵", "play", NotificationManager.IMPORTANCE_HIGH) manager.createNotificationChannel(channel) val notification = NotificationCompat.Builder(this, "壹点灵").build() startForeground(1, notification) } } private fun showWindow() { mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager val outMetrics = DisplayMetrics() mWindowManager.defaultDisplay.getMetrics(outMetrics) var layoutParams = WindowManager.LayoutParams().apply { type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE } flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE format = PixelFormat.RGBA_8888 width = outMetrics.widthPixels - dp2px(32F) height = WRAP_CONTENT gravity = Gravity.LEFT or Gravity.TOP x = outMetrics.widthPixels /2 - width / 2 y = outMetrics.heightPixels - dp2px(140F) } floatRootView = LayoutInflater.from(this).inflate(R.layout.layout_meditation_play_float_view, null) ivClose = floatRootView?.findViewById(R.id.iv_close) ivCover = floatRootView?.findViewById(R.id.iv_cover) tvTitle = floatRootView?.findViewById(R.id.tv_title) ivProgress = floatRootView?.findViewById(R.id.progress_bar) ivPlayOrPause = floatRootView?.findViewById(R.id.iv_play_status) floatRootView?.setOnTouchListener(FloatViewTouchListener(layoutParams, mWindowManager)) mWindowManager.addView(floatRootView, layoutParams) windowIsShow = true } fun onEventMainThread(event: Any) { if (event is com.ydl.ydlcommon.event.MeditationFloatEvent){ if (event.show!=null && !event.show) { if (event.stop == true){ try { mMediaPlayer?.stop() }catch (e:Exception){ } hideFloatWindow() } hideFloatWindow() } } if (event is MeditationFloatEvent){ if (event.time!=null){ if (event.time>0){ initRxTimeOff(event.time) }else{ mDisposable?.dispose() } }else{ if (event.show!=null && !event.show) { if (event.stop == true){ try { mMediaPlayer?.stop() }catch (e:Exception){ } hideFloatWindow() } hideFloatWindow() } if (event.show!=null && event.show && event.meditation != null) { if (!windowIsShow) { showWindow() } updateFloatView(event.meditation) } } } } private fun updateFloatView(meditation: MeditationPlayModuleBean.MeditationDetail) { currentMediaId = meditation.mediaId MediaPlayerManager.getInstance(this)?.setMediaId(currentMediaId) mMediaPlayer = MediaPlayerManager.getInstance(this)?.getMediaPlayer() tvTitle?.setOnClickListener { //悬浮窗暂停点击事件 ActionCountUtils.count(MuseBIConstants.YDL_MUSE_MEDITATION_WINDOW_CLICK,"") val intent = Intent(this, PlayMeditationActivity::class.java) intent.putExtra("MEDIA_ID", meditation.mediaId) intent.putExtra("MEDITATION_ID", meditation.meditationId) intent.putExtra("MEDITATION_TYPE", meditation.meditationType) intent.putExtra("MEDIA_COVER_URL", meditation.coverImageUrl) intent.putExtra("MEDIA_URL", meditation.mediaUrl) intent.flags = FLAG_ACTIVITY_NEW_TASK startActivity(intent) } ivCover?.setOnClickListener { //悬浮窗暂停点击事件 ActionCountUtils.count(MuseBIConstants.YDL_MUSE_MEDITATION_WINDOW_CLICK,"") val intent = Intent(this, PlayMeditationActivity::class.java) intent.putExtra("MEDIA_ID", meditation.mediaId) intent.putExtra("MEDITATION_ID", meditation.meditationId) intent.putExtra("MEDITATION_TYPE", meditation.meditationType) intent.putExtra("MEDIA_COVER_URL", meditation.coverImageUrl) intent.putExtra("MEDIA_URL", meditation.mediaUrl) intent.flags = FLAG_ACTIVITY_NEW_TASK startActivity(intent) } if (mMediaPlayer?.isPlaying == true) { ivPlayOrPause?.setImageResource(R.drawable.icon_meditation_float_play) } else { ivPlayOrPause?.setImageResource(R.drawable.icon_meditation_float_pause) } ivProgress?.maxProcess = mMediaPlayer?.duration ?: 0 ivProgress?.curProcess = mMediaPlayer?.currentPosition ?: 0 Glide.with(floatRootView!!) .load(meditation.coverImageUrl) .into(ivCover!!) tvTitle?.text = meditation.title ivPlayOrPause?.setOnClickListener { if (mMediaPlayer?.isPlaying == true) { //悬浮窗暂停点击事件 ActionCountUtils.count(MuseBIConstants.YDL_MUSE_MEDITATION_WINDOW_PAUSE_CLICK,"") MediaPlayerManager.getInstance(this)?.pause() if (meditation.meditationId != null && meditation.mediaId != null) { MuseHttp.getInstance().postMeditationPlayRecord( meditationId = meditation.meditationId!!.toInt(), isQuit = 1, mediaId = meditation.mediaId!!, playTime = (ivProgress?.curProcess?.div(1000.00))?.roundToInt() ?: 0, isComplete = 0 ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ }, { object : ThrowableConsumer() { override fun accept(msg: String) { } } }) } } else { //悬浮窗播放点击事件 ActionCountUtils.count(MuseBIConstants.YDL_MUSE_MEDITATION_WINDOW_PLAY_CLICK,"") MediaPlayerManager.getInstance(this)?.play() } if (mMediaPlayer?.isPlaying == true) { ivPlayOrPause?.setImageResource(R.drawable.icon_meditation_float_play) } else { ivPlayOrPause?.setImageResource(R.drawable.icon_meditation_float_pause) } } mTimer.schedule(object : TimerTask() { override fun run() { ivProgress?.curProcess = mMediaPlayer?.currentPosition ?: 0 } }, 0, 50) mMediaPlayer?.setOnCompletionListener { val duration = meditation?.duration?.toInt()?:0 val currentDuration = (mMediaPlayer?.currentPosition?:0)/1000 if(meditation.mediaId!=null && meditation.meditationId!=null){ val playTime = (ivProgress?.curProcess?.div(1000.00))?.roundToInt() ?: 0 if(duration == currentDuration){ MediaPlayerTimeUtil.uploadPlayRecord( meditationId = meditation.meditationId.toInt(), mediaId = meditation.mediaId, isQuit = 0, playTime = playTime, isComplete = 1 ) } } if (mMediaPlayer?.isPlaying == true) { ivPlayOrPause?.setImageResource(R.drawable.icon_meditation_float_play) } else { ivPlayOrPause?.setImageResource(R.drawable.icon_meditation_float_pause) } } ivClose?.setOnClickListener { //悬浮窗关闭点击事件 ActionCountUtils.count(MuseBIConstants.YDL_MUSE_MEDITATION_WINDOW_CLOSE_CLICK,"") if(meditation.mediaId!=null && meditation.meditationId!=null){ val playTime = (ivProgress?.curProcess?.div(1000.00))?.roundToInt() ?: 0 MediaPlayerTimeUtil.uploadPlayRecord( meditationId = meditation.meditationId.toInt(), mediaId = meditation.mediaId, isQuit = 0, playTime = playTime, isComplete = 0 ) } MediaPlayerManager.getInstance(this)?.stop() hideFloatWindow() } } private fun hideFloatWindow() { if (floatRootView != null && floatRootView?.windowToken != null) { if (mWindowManager != null) { windowIsShow = false mWindowManager.removeViewImmediate(floatRootView) } } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { return super.onStartCommand(intent, flags, startId) } override fun startForegroundService(service: Intent?): ComponentName? { return super.startForegroundService(service) } override fun onDestroy() { super.onDestroy() if (EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().unregister(this) } mDisposable?.dispose() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) { stopForeground(true) } } override fun onBind(intent: Intent?): IBinder? { return MeditationBinder() } private fun dp2px(dp: Float): Int { val scale = resources.displayMetrics.density return (dp * scale + 0.5f).toInt() } private fun initRxTimeOff(time: Long) { mObservable = Observable.interval(0, 1, TimeUnit.SECONDS) .take(time / 1000 + 1) .map { t -> time - t * 1000 } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) mObserver = object : Observer<Long> { override fun onSubscribe(d: Disposable) { mDisposable = d } override fun onNext(t: Long) { } override fun onError(e: Throwable) { } override fun onComplete() { if (mMediaPlayer?.isPlaying == true) { mMediaPlayer?.stop() ivPlayOrPause?.setImageResource(R.drawable.icon_meditation_float_pause) } hideFloatWindow() } } if (mObserver != null && mObserver is Observer<Long>) { mObservable?.subscribe(mObserver as Observer<Long>) } if (mDisposable?.isDisposed == true && mObserver != null && mObserver is Observer<Long>) { mObservable?.subscribe(mObserver as Observer<Long>) } } }