Commit 5305185d by 范玉宾

meditation play float view

parent 09ce85ea
......@@ -30,6 +30,8 @@ import com.yidianling.common.tools.LogUtil
import com.yidianling.common.tools.ToastUtil
import com.yidianling.consultant.api.IConsultantService
import com.yidianling.fm.api.service.IFMService
import com.yidianling.muse.helper.MediaPlayerManager
import com.yidianling.muse.service.MeditationWindowService
import com.yidianling.tests.home.NewTestHomeActivity
import com.yidianling.user.StatusUtils
import com.yidianling.user.ui.collect.CollectSexAndBirthActivity
......@@ -52,6 +54,8 @@ class MainActivity : BaseLceActivity<DemoContract.View, DemoContract.Presenter>(
private var secretDialog: SecretDialog? = null
protected var playService: PlayService? = null
private var meditationIntent:Intent?=null
override fun getContentViewId(): Int {
return R.id.lce_content_view
}
......@@ -82,6 +86,10 @@ class MainActivity : BaseLceActivity<DemoContract.View, DemoContract.Presenter>(
// 初始化一键登录sdk
OneKeyLoginHelp.sdkInit(this, OneKeyLoginHelp.YDL_USER_APP, PhoneNumberAuthHelper.SERVICE_TYPE_LOGIN)
bindService()
meditationIntent = Intent(this,MeditationWindowService::class.java)
startService(meditationIntent)
reLoadData()
requestPermission()
bt_mdt.setOnClickListener {
......@@ -273,6 +281,10 @@ class MainActivity : BaseLceActivity<DemoContract.View, DemoContract.Presenter>(
if (serviceConnection != null) {
unbindService(serviceConnection)
}
if(meditationIntent!=null){
MediaPlayerManager.getInstance(this)?.stop()
stopService(meditationIntent)
}
super.onDestroy()
}
......@@ -286,7 +298,6 @@ class MainActivity : BaseLceActivity<DemoContract.View, DemoContract.Presenter>(
}
}
private fun showEnsureDialog() {
secretDialog = SecretDialog(this, object : OnSecretDialogListener {
override fun onCancel() {
......
......@@ -9,12 +9,12 @@ ext {
"m-consultant" : "0.0.60.25",
"m-fm" : "0.0.30.08",
"m-user" : "0.0.62.12",
"m-home" : "0.0.23.56",
"m-home" : "0.0.23.57",
"m-im" : "0.0.21.44",
"m-dynamic" : "0.0.7.73",
"m-article" : "0.0.0.10",
"m-muse" : "0.0.28.35",
"m-muse" : "0.0.28.36",
"m-tests" : "0.0.24.18",
"m-course" : "0.0.43.37",
......@@ -94,12 +94,12 @@ ext {
"m-consultant" : "0.0.60.25",
"m-fm" : "0.0.30.08",
"m-user" : "0.0.62.12",
"m-home" : "0.0.23.56",
"m-home" : "0.0.23.57",
"m-im" : "0.0.21.44",
"m-dynamic" : "0.0.7.73",
"m-article" : "0.0.0.8",
"m-muse" : "0.0.28.35",
"m-muse" : "0.0.28.36",
"m-tests" : "0.0.24.18",
"m-course" : "0.0.43.37",
//-------------- 业务模块 API 层 --------------
......
......@@ -22,12 +22,12 @@ import kotlinx.android.synthetic.ydl.home_fragment.*
class MeditationTypeAdapter(
private val context: Context,
private val data: List<MeditationModuleBean.MeditationDetail>,
private val moreLink: String,
private val data: List<MeditationModuleBean.MeditationDetail>?,
private val moreLink: String?,
private val homeLink:String?=null,
private val cateId:Long?=null,
private val mark:Int?=null,
private val meditationType: Int
private val meditationType: Int? = null
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
......@@ -54,13 +54,13 @@ class MeditationTypeAdapter(
is MeditationTypeViewHolder -> {
holder.ivType?.let {
Glide.with(context)
.load(data[position].coverImageUrl)
.load(data?.get(position)?.coverImageUrl)
.transition(DrawableTransitionOptions.withCrossFade())
.into(it)
}
holder.tvName?.let {
it.text = data[position].title
it.text = data?.get(position)?.title ?: ""
}
holder.cvLayout?.setOnClickListener {
......@@ -72,8 +72,11 @@ class MeditationTypeAdapter(
if(!ModularServiceManager.provide(IUserService::class.java).loginByOneKeyLogin(context,true)){
return@setOnClickListener
}
if(data==null){
return@setOnClickListener
}
ARouter.getInstance().build("/muse/play")
.withLong("MEDITATION_ID", data[position].meditationId)
.withLong("MEDITATION_ID", data[position]?.meditationId)
.withInt("MEDITATION_TYPE", meditationType)
.withFloat("MEDIA_DURATION", data[position].duration?:0.0f)
.withString("MEDIA_URL", data[position].mediaIdCoverImageUrl)
......@@ -84,7 +87,10 @@ class MeditationTypeAdapter(
//防止连击
return@setOnClickListener
}
val homeLink = "${homeLink}mark=$mark&cateId=$cateId&meditationId=${data[position].meditationId}"
if(data==null){
return@setOnClickListener
}
val homeLink = "${homeLink}mark=$mark&cateId=$cateId&meditationId=${data[position]?.meditationId}"
if (!homeLink.isNullOrBlank()) {
NewH5Activity.start(context, H5Params(homeLink, null))
}
......@@ -108,17 +114,17 @@ class MeditationTypeAdapter(
}
override fun getItemCount(): Int {
return if (data.isNotEmpty()) {
return if (data?.isNotEmpty() == true) {
data.size + 1
} else {
data.size
0
}
}
override fun getItemId(position: Int) = position.toLong()
override fun getItemViewType(position: Int): Int {
return if (data.isNotEmpty() && position == data.size) {
return if (data?.isNotEmpty() == true && position == data.size) {
FOOTER_TYPE
} else {
CONTENT_TYPE
......
......@@ -59,11 +59,11 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.github.weidongjian:androidWheelView:1.0.0'
implementation 'com.github.feeeei:CircleSeekbar:v1.1.2'
// solve build problem
// cannot access 'androidx.lifecycle.hasdefaultviewmodelproviderfactory'
// Comment out when compiling
// implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
implementation "com.alibaba:arouter-api:$arouter_api"
// 注意此处的依赖方式:kotlin中使用和java中使用方式有不同
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yidianling.muse">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application>
<activity
android:name=".activity.MuseActivity"
......@@ -18,5 +21,8 @@
android:name=".activity.MeditationTimeOffActivity"
android:screenOrientation="portrait"
android:theme="@style/platform_NoTitleTheme" />
<service android:name=".service.MeditationWindowService"/>
</application>
</manifest>
......@@ -3,6 +3,7 @@ package com.yidianling.muse.activity
import android.content.Intent
import android.media.MediaPlayer
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.widget.SeekBar
import com.alibaba.android.arouter.facade.annotation.Route
......@@ -23,6 +24,7 @@ import com.yidianling.common.tools.ToastUtil
import com.yidianling.home.http.MuseHttp
import com.yidianling.muse.R
import com.yidianling.muse.bean.MeditationPlayModuleBean
import com.yidianling.muse.event.MeditationFloatEvent
import com.yidianling.muse.helper.MediaPlayerManager
import com.yidianling.muse.utils.MediaPlayerTimeUtil
import com.yidianling.muse.widget.QuitMeditationDialog
......@@ -127,6 +129,9 @@ class PlayMeditationActivity : BaseActivity() {
mediaListLink = module.playDetailUrl
module.mediaList?.forEach { meditationPlayBean ->
if (meditationPlayBean.mediaId == mediaId) {
currentMeditation = meditationPlayBean.copy(mediaType = meditationType,meditationId = meditationId!!)
mediaId = module?.mediaId ?: 0L
val title = meditationPlayBean.title ?: "未知标题"
val desc = meditationPlayBean.desc ?: ""
......@@ -188,7 +193,7 @@ class PlayMeditationActivity : BaseActivity() {
if (meditationPlayBean.mediaId == mediaId) {
currentMeditation = meditationPlayBean
currentMeditation = meditationPlayBean.copy(meditationId = meditationId!!)
mediaId = module?.mediaId ?: 0L
val title = meditationPlayBean.title
......@@ -239,6 +244,9 @@ class PlayMeditationActivity : BaseActivity() {
}
private fun updateUIByMeditationType() {
val event = MeditationFloatEvent(false)
EventBus.getDefault().post(event)
// 声音类型
if (meditationType == 0) {
exo_rew.visibility = View.GONE
......@@ -370,7 +378,17 @@ class PlayMeditationActivity : BaseActivity() {
}
iv_back.setOnClickListener {
finish()
// MeditationViewModel.isVisible.postValue(true)
// MeditationViewModel.meditation.postValue(currentMeditation)
// MeditationViewModel.meditations.postValue(meditations as ArrayList<MeditationPlayModuleBean.MeditationDetail>)
// LogUtil.d("Lancet=======","post $currentMeditation")
val event = MeditationFloatEvent(true,meditationDetail = currentMeditation)
EventBus.getDefault().post(event)
Handler().postDelayed({
finish()
},300)
}
iv_share.setOnClickListener {
......@@ -447,7 +465,7 @@ class PlayMeditationActivity : BaseActivity() {
postPlayRecord(isQuit = 0, playTime = 0, isComplete = 0)
val meditation = meditations[currentPosition - 1]
currentMeditation = meditation
currentMeditation = meditation.copy(meditationId = meditationId!!)
mediaId = meditation.mediaId
val mediaCoverUrl = meditation.coverImageUrl
......@@ -567,7 +585,7 @@ class PlayMeditationActivity : BaseActivity() {
mMediaPlayer?.setOnCompletionListener {
postPlayRecord(isQuit = 0,
playTime = mMediaPlayer?.duration?:0,
playTime = (seekbar_play_progress.progress / 1000.00).roundToInt(),
isComplete = 1)
isPlaying = if (it.isPlaying) {
exo_play.setImageResource(R.drawable.icon_pause_play)
......
......@@ -16,7 +16,9 @@ class MeditationPlayModuleBean : HomeItemBaseBean {
var mediaList: ArrayList<MeditationDetail>? = null
data class MeditationDetail(
val mediaId:Long,
val mediaType:Int? = null,
val mediaId:Long?=null,
val meditationId:Long,
val title:String,
val author:String,
val coverImageUrl:String,
......@@ -30,4 +32,8 @@ class MeditationPlayModuleBean : HomeItemBaseBean {
val coverImageUrlIcon:String
)
override fun toString(): String {
return "MeditationPlayModuleBean(meditationId=$meditationId, mediaId=$mediaId, mediaType=$mediaType, playDetailUrl=$playDetailUrl, mediaList=$mediaList)"
}
}
\ No newline at end of file
package com.yidianling.muse.event
import com.yidianling.muse.bean.MeditationPlayModuleBean
class MeditationFloatEvent(
val show: Boolean,
val meditationDetail: MeditationPlayModuleBean.MeditationDetail?=null
)
\ No newline at end of file
......@@ -3,9 +3,10 @@ package com.yidianling.muse.helper
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import com.ydl.ydlcommon.utils.LogUtil
class FloatViewTouchListener(val wl: WindowManager.LayoutParams,val windowManager: WindowManager):
View.OnTouchListener{
class FloatViewTouchListener(val wl: WindowManager.LayoutParams, val windowManager: WindowManager) :
View.OnTouchListener {
private var x = 0
private var y = 0
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
......@@ -26,6 +27,8 @@ View.OnTouchListener{
x += movedX
y += movedY
}
LogUtil.d("Lancet=======","nowY=====$nowY")
LogUtil.d("Lancet=======","movedY=====$movedY")
//更新悬浮窗位置
windowManager.updateViewLayout(view, wl)
}
......
package com.yidianling.muse.helper
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
object MeditationViewModel: ViewModel() {
//悬浮窗口创建 移除 基于无障碍服务
var isShowWindow = MutableLiveData<Boolean>()
//悬浮窗口创建 移除
var isShowSuspendWindow = MutableLiveData<Boolean>()
//悬浮窗口显示 隐藏
var isVisible = MutableLiveData<Boolean>()
}
\ No newline at end of file
package com.yidianling.muse.service
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.graphics.PixelFormat
import android.media.MediaPlayer
import android.os.Build
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.lifecycle.LifecycleService
import com.bumptech.glide.Glide
import com.ydl.ydlcommon.data.http.ThrowableConsumer
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.event.MeditationFloatEvent
import com.yidianling.muse.helper.FloatViewTouchListener
import com.yidianling.muse.helper.MediaPlayerManager
import de.greenrobot.event.EventBus
import io.feeeei.circleseekbar.CircleSeekBar
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.util.*
import kotlin.math.roundToInt
class MeditationWindowService : LifecycleService() {
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 windowIsShow = false
override fun onCreate() {
super.onCreate()
EventBus.getDefault().register(this)
}
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.CENTER_HORIZONTAL or Gravity.BOTTOM
}
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: MeditationFloatEvent) {
if (!event.show) {
hideFloatWindow()
}
if (event.show && event.meditationDetail != null) {
if (!windowIsShow) {
showWindow()
}
updateFloatView(event.meditationDetail)
}
}
private fun updateFloatView(meditation: MeditationPlayModuleBean.MeditationDetail) {
mMediaPlayer = MediaPlayerManager.getInstance(this)?.getMediaPlayer()
floatRootView?.setOnClickListener {
val intent = Intent(this, PlayMeditationActivity::class.java)
intent.putExtra("MEDIA_ID", meditation.mediaId)
intent.putExtra("MEDITATION_ID", meditation.meditationId)
intent.putExtra("MEDITATION_TYPE", meditation.mediaType)
intent.putExtra("MEDIA_COVER_URL", meditation.coverImageUrl)
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) {
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 {
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 {
postPlayRecord(
0, (ivProgress?.curProcess?.div(1000.00))?.roundToInt() ?: 0,
1,
meditation.meditationId.toInt(),
meditation.mediaId ?: 0L
)
}
ivClose?.setOnClickListener {
postPlayRecord(
1, (ivProgress?.curProcess?.div(1000.00))?.roundToInt() ?: 0,
0,
meditation.meditationId.toInt(),
meditation.mediaId ?: 0L
)
MediaPlayerManager.getInstance(this)?.stop()
hideFloatWindow()
}
}
private fun hideFloatWindow() {
if (floatRootView != null && floatRootView?.windowToken != null) {
if (mWindowManager != null) {
windowIsShow = false
mTimer.cancel()
mWindowManager.removeViewImmediate(floatRootView)
}
}
}
override fun onDestroy() {
super.onDestroy()
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this)
}
}
private fun dp2px(dp: Float): Int {
val scale = resources.displayMetrics.density
return (dp * scale + 0.5f).toInt()
}
private fun postPlayRecord(
isQuit: Int,
playTime: Int,
isComplete: Int,
meditationId: Int,
mediaId: Long
) {
MuseHttp.getInstance().postMeditationPlayRecord(
meditationId = meditationId,
isQuit = isQuit, mediaId = mediaId,
playTime = playTime,
isComplete = isComplete
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
}, {
object : ThrowableConsumer() {
override fun accept(msg: String) {
}
}
})
}
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="8dp"
android:height="9dp"
android:viewportWidth="8"
android:viewportHeight="9">
<path
android:pathData="M6.64877,5.7528L1.82138,8.7257C1.46481,8.94528 0.99774,8.83422 0.77811,8.47766C0.7045,8.35811 0.66553,8.22046 0.66553,8.08006L0.66553,0.84302C0.66553,0.42426 1.005,0.08478 1.42377,0.08478C1.56418,0.08478 1.70181,0.12375 1.82138,0.19738L6.64877,3.17028C7.36191,3.60946 7.58401,4.54359 7.14481,5.25674C7.02051,5.4586 6.85062,5.62849 6.64877,5.7528L6.64877,5.7528Z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="9dp"
android:height="9dp"
android:viewportWidth="9"
android:viewportHeight="9">
<path
android:pathData="M1.97559,0.16724C2.66594,0.16724 3.22559,0.72688 3.22559,1.41724L3.22559,6.91724C3.22559,7.60759 2.66594,8.16724 1.97559,8.16724C1.28523,8.16724 0.72559,7.60759 0.72559,6.91724L0.72559,1.41724C0.72559,0.72688 1.28523,0.16724 1.97559,0.16724Z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M6.97559,0.16724C7.66594,0.16724 8.22559,0.72688 8.22559,1.41724L8.22559,6.91724C8.22559,7.60759 7.66594,8.16724 6.97559,8.16724C6.28523,8.16724 5.72559,7.60759 5.72559,6.91724L5.72559,1.41724C5.72559,0.72688 6.28523,0.16724 6.97559,0.16724Z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>
......@@ -2,6 +2,9 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/bg_play_meditation_float_view"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
......@@ -9,9 +12,8 @@
android:id="@+id/csl_root_layout"
android:layout_width="match_parent"
android:layout_height="56dp"
tools:background="@drawable/play_float_background"
android:background="@drawable/bg_play_meditation_float_view"
android:layout_marginHorizontal="16dp">
tools:background="@drawable/play_float_background">
<ImageView
android:id="@+id/iv_close"
......@@ -40,6 +42,7 @@
android:id="@+id/iv_cover"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="centerCrop"
android:src="@drawable/platform_loading_logo"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
......@@ -67,17 +70,23 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ProgressBar
<io.feeeei.circleseekbar.CircleSeekBar
android:id="@+id/progress_bar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center" />
android:layout_gravity="center"
app:wheel_unreached_color="#FF282E3F"
app:wheel_reached_color="#FFFFFF"
app:wheel_unreached_width="2dp"
app:wheel_reached_width="2dp"/>
<ImageView
android:id="@+id/iv_play_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
android:layout_width="20dp"
android:layout_height="20dp"
android:padding="5dp"
android:layout_gravity="center"
android:src="@drawable/icon_meditation_float_pause"/>
</FrameLayout>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment