Compare commits

...

3 Commits

Author SHA1 Message Date
fbe86451ba 暫時加上flag 2023-07-03 12:19:08 +08:00
7ac9063248 拿掉其他懸浮窗範例 2023-07-01 11:17:15 +08:00
bbe99a1ca5 註解繁體化 2023-07-01 10:48:59 +08:00
13 changed files with 171 additions and 174 deletions

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">

View File

@ -8,6 +8,7 @@ import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import android.view.* import android.view.*
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.ImageView
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import com.ray650128.floatwindowdemo.databinding.ActivityMainBinding import com.ray650128.floatwindowdemo.databinding.ActivityMainBinding
@ -15,7 +16,7 @@ import com.ray650128.floatwindowdemo.utils.Utils.REQUEST_FLOAT_CODE
import com.ray650128.floatwindowdemo.service.SuspendwindowService import com.ray650128.floatwindowdemo.service.SuspendwindowService
import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener
import com.ray650128.floatwindowdemo.utils.Utils import com.ray650128.floatwindowdemo.utils.Utils
import com.ray650128.floatwindowdemo.utils.ViewModleMain import com.ray650128.floatwindowdemo.utils.ViewModelMain
/** /**
* @功能: 悬浮窗口Demo * @功能: 悬浮窗口Demo
@ -25,7 +26,6 @@ import com.ray650128.floatwindowdemo.utils.ViewModleMain
*/ */
class MainActivity : AppCompatActivity(), View.OnClickListener { class MainActivity : AppCompatActivity(), View.OnClickListener {
private var floatRootView: View? = null//悬浮窗View
private var isReceptionShow = false private var isReceptionShow = false
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
@ -38,80 +38,20 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
startService(Intent(this, SuspendwindowService::class.java)) startService(Intent(this, SuspendwindowService::class.java))
binding.apply { binding.apply {
bt01.setOnClickListener(this@MainActivity)
bt02.setOnClickListener(this@MainActivity)
bt03.setOnClickListener(this@MainActivity) bt03.setOnClickListener(this@MainActivity)
bt04.setOnClickListener(this@MainActivity)
bt05.setOnClickListener(this@MainActivity)
} }
} }
override fun onClick(v: View?) { override fun onClick(v: View?) {
when (v?.id) { when (v?.id) {
R.id.bt_01 -> {
showCurrentWindow()
}
R.id.bt_02 -> {
Utils.checkSuspendedWindowPermission(this) {
isReceptionShow = false
ViewModleMain.isShowSuspendWindow.postValue(true)
}
}
R.id.bt_03 -> { R.id.bt_03 -> {
Utils.checkAccessibilityPermission(this) { Utils.checkAccessibilityPermission(this) {
ViewModleMain.isShowWindow.postValue(true) ViewModelMain.isShowWindow.postValue(true)
} }
} }
R.id.bt_04 -> {
Utils.checkSuspendedWindowPermission(this) {
isReceptionShow = true
ViewModleMain.isShowSuspendWindow.postValue(true)
}
}
R.id.bt_05 -> {
closeAllSuspendWindow()
}
} }
} }
/**
* 应用界面内显示悬浮球
*/
@SuppressLint("ClickableViewAccessibility")
private fun showCurrentWindow() {
var layoutParam = WindowManager.LayoutParams().apply {
//设置大小 自适应
width = WRAP_CONTENT
height = WRAP_CONTENT
flags =
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
}
// 新建悬浮窗控件
floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null)
//设置拖动事件
floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager))
// 将悬浮窗控件添加到WindowManager
windowManager.addView(floatRootView, layoutParam)
}
/**
* 关闭所有悬浮窗
*/
fun closeAllSuspendWindow() {
if (!Utils.isNull(floatRootView)) {
if (!Utils.isNull(floatRootView?.windowToken)) {
if (!Utils.isNull(windowManager)) {
windowManager?.removeView(floatRootView)
}
}
}
ViewModleMain.isShowSuspendWindow.postValue(false)
ViewModleMain.isShowWindow.postValue(false)
}
@RequiresApi(api = Build.VERSION_CODES.M)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_FLOAT_CODE) { if (requestCode == REQUEST_FLOAT_CODE) {
if (Settings.canDrawOverlays(this)) { if (Settings.canDrawOverlays(this)) {
@ -124,21 +64,20 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (isReceptionShow) { if (isReceptionShow) {
ViewModleMain.isVisible.postValue(true) ViewModelMain.isVisible.postValue(true)
} }
binding.textView.text = "onResume" binding.textView.text = "onResume"
} }
override fun onPause() { override fun onPause() {
super.onPause()
binding.textView.text = "onPause" binding.textView.text = "onPause"
super.onPause()
} }
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
if (isReceptionShow) { if (isReceptionShow) {
ViewModleMain.isVisible.postValue(false) ViewModelMain.isVisible.postValue(false)
} }
} }
} }

View File

@ -0,0 +1,9 @@
package com.ray650128.floatwindowdemo
import android.content.res.Resources
val Int.dp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
val Int.px: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()

View File

@ -9,18 +9,18 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import androidx.lifecycle.LifecycleService import androidx.lifecycle.LifecycleService
import com.ray650128.floatwindowdemo.R import com.ray650128.floatwindowdemo.R
import com.ray650128.floatwindowdemo.utils.Utils import com.ray650128.floatwindowdemo.utils.Utils
import com.ray650128.floatwindowdemo.utils.ViewModleMain import com.ray650128.floatwindowdemo.utils.ViewModelMain
import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener
/** /**
* @功能:应用外打开Service 有局限性 特殊界面无法显 * @功能:應用外打開Service 有侷限性 特殊界面無法顯
* @User Lmy * @User Lmy
* @Creat 4/15/21 5:28 PM * @Creat 4/15/21 5:28 PM
* @Compony 远相信美好的事情即将发 * @Compony 遠相信美好的事情即將發
*/ */
class SuspendwindowService : LifecycleService() { class SuspendwindowService : LifecycleService() {
private lateinit var windowManager: WindowManager private lateinit var windowManager: WindowManager
private var floatRootView: View? = null//浮窗View private var floatRootView: View? = null//浮窗View
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -28,18 +28,18 @@ class SuspendwindowService : LifecycleService() {
} }
/** /**
* 初始化订阅 * 初始化訂閱
*/ */
private fun initObserve() { private fun initObserve() {
ViewModleMain.apply { ViewModelMain.apply {
/** /**
* 悬浮窗按钮的显示和隐 * 懸浮窗按鈕的顯示和隱
*/ */
isVisible.observe(this@SuspendwindowService, { isVisible.observe(this@SuspendwindowService, {
floatRootView?.visibility = if (it) View.VISIBLE else View.GONE floatRootView?.visibility = if (it) View.VISIBLE else View.GONE
}) })
/** /**
* 悬浮窗按钮的创建和移除 * 懸浮窗按鈕的建立和移除
*/ */
isShowSuspendWindow.observe(this@SuspendwindowService, { isShowSuspendWindow.observe(this@SuspendwindowService, {
if (it) { if (it) {
@ -58,17 +58,17 @@ class SuspendwindowService : LifecycleService() {
} }
/** /**
* 创建悬浮窗 * 建立懸浮窗
*/ */
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private fun showWindow() { private fun showWindow() {
//取WindowManager //取WindowManager
windowManager = getSystemService(WINDOW_SERVICE) as WindowManager windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
val outMetrics = DisplayMetrics() val outMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(outMetrics) windowManager.defaultDisplay.getMetrics(outMetrics)
var layoutParam = WindowManager.LayoutParams().apply { var layoutParam = WindowManager.LayoutParams().apply {
/** /**
* 设置type 这里进行了兼 * 設定type 這裡進行了相
*/ */
type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
@ -77,18 +77,18 @@ class SuspendwindowService : LifecycleService() {
} }
format = PixelFormat.RGBA_8888 format = PixelFormat.RGBA_8888
flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//位置大小设置 //位置大小設定
width = WRAP_CONTENT width = WRAP_CONTENT
height = WRAP_CONTENT height = WRAP_CONTENT
gravity = Gravity.LEFT or Gravity.TOP gravity = Gravity.LEFT or Gravity.TOP
//设置剧中屏幕显 //設定劇中螢幕顯
x = outMetrics.widthPixels / 2 - width / 2 x = outMetrics.widthPixels / 2 - width / 2
y = outMetrics.heightPixels / 2 - height / 2 y = outMetrics.heightPixels / 2 - height / 2
} }
// 新建悬浮窗控 // 新建懸浮窗控制元
floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null) floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null)
floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager)) floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager))
// 将悬浮窗控件添加到WindowManager // 將懸浮窗控制元件新增到WindowManager
windowManager.addView(floatRootView, layoutParam) windowManager.addView(floatRootView, layoutParam)
} }
} }

View File

@ -5,27 +5,48 @@ import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.graphics.PixelFormat import android.graphics.PixelFormat
import android.os.Build import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.* import android.view.*
import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityEvent
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.LifecycleRegistry
import com.ray650128.floatwindowdemo.R import com.ray650128.floatwindowdemo.R
import com.ray650128.floatwindowdemo.dp
import com.ray650128.floatwindowdemo.px
import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener
import com.ray650128.floatwindowdemo.utils.Utils.isNull import com.ray650128.floatwindowdemo.utils.Utils.isNull
import com.ray650128.floatwindowdemo.utils.ViewModleMain import com.ray650128.floatwindowdemo.utils.ViewModelMain
import java.text.SimpleDateFormat
/** /**
* @功能:利用无障碍打开悬浮窗口 无局限性 任何界面可以显 * @功能:利用無障礙打開懸浮視窗 無侷限性 任何界面可以顯
* @User Lmy * @User Lmy
* @Creat 4/15/21 5:57 PM * @Creat 4/15/21 5:57 PM
* @Compony 远相信美好的事情即将发 * @Compony 遠相信美好的事情即將發
*/ */
class WorkAccessibilityService : AccessibilityService(), LifecycleOwner { class WorkAccessibilityService : AccessibilityService(), LifecycleOwner {
private lateinit var windowManager: WindowManager private lateinit var windowManager: WindowManager
private var floatRootView: View? = null//浮窗View private var floatRootView: View? = null//浮窗View
private val mLifecycleRegistry = LifecycleRegistry(this) private val mLifecycleRegistry = LifecycleRegistry(this)
private val timeUpdateHandler = Handler(Looper.getMainLooper())
private val timeUpdateRunnable = object : Runnable {
@SuppressLint("SimpleDateFormat")
override fun run() {
val now = System.currentTimeMillis()
val simpleDateFormat = SimpleDateFormat("HH:mm:ss")
floatRootView?.findViewById<TextView>(R.id.tv_time)?.text = simpleDateFormat.format(now)
timeUpdateHandler.postDelayed(this, 1000)
}
}
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
@ -33,10 +54,10 @@ class WorkAccessibilityService : AccessibilityService(), LifecycleOwner {
} }
/** /**
* 开关闭的订阅 * 開關閉的訂閱
*/ */
private fun initObserve() { private fun initObserve() {
ViewModleMain.isShowWindow.observe(this) { ViewModelMain.isShowWindow.observe(this) {
if (it) { if (it) {
showWindow() showWindow()
} else { } else {
@ -44,6 +65,7 @@ class WorkAccessibilityService : AccessibilityService(), LifecycleOwner {
if (!isNull(floatRootView?.windowToken)) { if (!isNull(floatRootView?.windowToken)) {
if (!isNull(windowManager)) { if (!isNull(windowManager)) {
windowManager.removeView(floatRootView) windowManager.removeView(floatRootView)
timeUpdateHandler.removeCallbacks(timeUpdateRunnable)
} }
} }
} }
@ -53,33 +75,36 @@ class WorkAccessibilityService : AccessibilityService(), LifecycleOwner {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private fun showWindow() { private fun showWindow() {
// 设置LayoutParam // 設定LayoutParam
// 获取WindowManager服务 // 獲取WindowManager服務
windowManager = getSystemService(WINDOW_SERVICE) as WindowManager windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
val outMetrics = DisplayMetrics() val outMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(outMetrics) windowManager.defaultDisplay.getMetrics(outMetrics)
var layoutParam = WindowManager.LayoutParams() val layoutParam = WindowManager.LayoutParams()
layoutParam.apply { layoutParam.apply {
//显示的位置 //顯示的位置
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY //劉海屏延伸到劉海里面
//刘海屏延伸到刘海里面
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
layoutInDisplayCutoutMode = layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
} }
} else { flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
} WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
flags = //flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
width = WindowManager.LayoutParams.WRAP_CONTENT width = 145.px
height = WindowManager.LayoutParams.WRAP_CONTENT height = 38.px
format = PixelFormat.TRANSPARENT format = PixelFormat.RGBA_8888
} }
floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null) floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null)
floatRootView?.findViewById<ImageView>(R.id.iv_close)?.setOnClickListener {
windowManager.removeView(floatRootView)
timeUpdateHandler.removeCallbacks(timeUpdateRunnable)
}
floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager)) floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager))
windowManager.addView(floatRootView, layoutParam) windowManager.addView(floatRootView, layoutParam)
timeUpdateHandler.post(timeUpdateRunnable)
} }
@ -89,9 +114,10 @@ class WorkAccessibilityService : AccessibilityService(), LifecycleOwner {
} }
override fun getLifecycle(): Lifecycle = mLifecycleRegistry override fun getLifecycle(): Lifecycle = mLifecycleRegistry
override fun onStart(intent: Intent?, startId: Int) {
super.onStart(intent, startId) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START) mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
return super.onStartCommand(intent, flags, startId)
} }
override fun onUnbind(intent: Intent?): Boolean { override fun onUnbind(intent: Intent?): Boolean {

View File

@ -1,25 +1,30 @@
package com.ray650128.floatwindowdemo.utils package com.ray650128.floatwindowdemo.utils
import android.util.Log
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
/** /**
* @功能:处理悬浮窗拖动更新位置 * @功能:處理懸浮窗拖動更新位置
* @User Lmy * @User Lmy
* @Creat 4/16/21 9:41 AM * @Creat 4/16/21 9:41 AM
* @Compony 远相信美好的事情即将发 * @Compony 遠相信美好的事情即將發
*/ */
class ItemViewTouchListener(val wl: WindowManager.LayoutParams, val windowManager: WindowManager) : class ItemViewTouchListener(val wl: WindowManager.LayoutParams, val windowManager: WindowManager) :
View.OnTouchListener { View.OnTouchListener {
private var x = 0 private var x = 0
private var y = 0 private var y = 0
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
Log.d("com.kldp.floating.floatingtools", "MotionEvent: $motionEvent")
when (motionEvent.action) { when (motionEvent.action) {
MotionEvent.ACTION_DOWN -> { MotionEvent.ACTION_DOWN -> {
wl.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
windowManager.updateViewLayout(view, wl)
x = motionEvent.rawX.toInt() x = motionEvent.rawX.toInt()
y = motionEvent.rawY.toInt() y = motionEvent.rawY.toInt()
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
val nowX = motionEvent.rawX.toInt() val nowX = motionEvent.rawX.toInt()
@ -32,13 +37,19 @@ class ItemViewTouchListener(val wl: WindowManager.LayoutParams, val windowManage
x += movedX x += movedX
y += movedY y += movedY
} }
//更新悬浮球控件位置 //更新懸浮球控制元件位置
windowManager?.updateViewLayout(view, wl) windowManager.updateViewLayout(view, wl)
}
MotionEvent.ACTION_OUTSIDE -> {
wl.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
windowManager.updateViewLayout(view, wl)
} }
else -> { else -> {
} }
} }
return false return true
} }
} }

View File

@ -14,18 +14,18 @@ import com.ray650128.floatwindowdemo.service.WorkAccessibilityService
import java.util.* import java.util.*
/** /**
* @功能: 工具 * @功能: 工具
* @User Lmy * @User Lmy
* @Creat 4/16/21 8:33 AM * @Creat 4/16/21 8:33 AM
* @Compony 远相信美好的事情即将发 * @Compony 遠相信美好的事情即將發
*/ */
object Utils { object Utils {
const val REQUEST_FLOAT_CODE=1001 const val REQUEST_FLOAT_CODE=1001
/** /**
* 转到设置页面申请打开无障碍辅助功能 * 轉到設定頁面申請打開無障礙輔助功能
*/ */
private fun accessibilityToSettingPage(context: Context) { private fun accessibilityToSettingPage(context: Context) {
//开启辅助功能页 //開啟輔助功能頁
try { try {
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -39,7 +39,7 @@ object Utils {
} }
/** /**
* 断Service是否开启 * 斷Service是否開啟
* *
*/ */
fun isServiceRunning(context: Context, ServiceName: String): Boolean { fun isServiceRunning(context: Context, ServiceName: String): Boolean {
@ -47,8 +47,7 @@ object Utils {
return false return false
} }
val myManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val myManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val runningService = val runningService = myManager.getRunningServices(1000) as ArrayList<ActivityManager.RunningServiceInfo>
myManager.getRunningServices(1000) as ArrayList<ActivityManager.RunningServiceInfo>
for (i in runningService.indices) { for (i in runningService.indices) {
if (runningService[i].service.className == ServiceName) { if (runningService[i].service.className == ServiceName) {
return true return true
@ -58,11 +57,10 @@ object Utils {
} }
/** /**
* 断悬浮窗权限权限 * 斷懸浮窗許可權許可權
*/ */
private fun commonROMPermissionCheck(context: Context?): Boolean { private fun commonROMPermissionCheck(context: Context?): Boolean {
var result = true var result = true
if (Build.VERSION.SDK_INT >= 23) {
try { try {
val clazz: Class<*> = Settings::class.java val clazz: Class<*> = Settings::class.java
val canDrawOverlays = val canDrawOverlays =
@ -71,18 +69,17 @@ object Utils {
} catch (e: Exception) { } catch (e: Exception) {
Log.e("ServiceUtils", Log.getStackTraceString(e)) Log.e("ServiceUtils", Log.getStackTraceString(e))
} }
}
return result return result
} }
/** /**
* 检查悬浮窗权限是否开启 * 檢查懸浮窗許可權是否開啟
*/ */
fun checkSuspendedWindowPermission(context: Activity, block: () -> Unit) { fun checkSuspendedWindowPermission(context: Activity, block: () -> Unit) {
if (commonROMPermissionCheck(context)) { if (commonROMPermissionCheck(context)) {
block() block()
} else { } else {
Toast.makeText(context, "请开启悬浮窗权限", Toast.LENGTH_SHORT).show() Toast.makeText(context, "請開啟懸浮窗許可權", Toast.LENGTH_SHORT).show()
context.startActivityForResult(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply { context.startActivityForResult(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply {
data = Uri.parse("package:${context.packageName}") data = Uri.parse("package:${context.packageName}")
}, REQUEST_FLOAT_CODE) }, REQUEST_FLOAT_CODE)
@ -90,7 +87,7 @@ object Utils {
} }
/** /**
* 检查无障碍服务权限是否开启 * 檢查無障礙服務許可權是否開啟
*/ */
fun checkAccessibilityPermission(context: Activity, block: () -> Unit) { fun checkAccessibilityPermission(context: Activity, block: () -> Unit) {
if (isServiceRunning(context, WorkAccessibilityService::class.java.canonicalName)) { if (isServiceRunning(context, WorkAccessibilityService::class.java.canonicalName)) {

View File

@ -1,23 +1,22 @@
package com.ray650128.floatwindowdemo.utils package com.ray650128.floatwindowdemo.utils
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
/** /**
* @功能: 于和Service通信 * @功能: 於和Service通訊
* @User Lmy * @User Lmy
* @Creat 4/16/21 8:37 AM * @Creat 4/16/21 8:37 AM
* @Compony 远相信美好的事情即将发 * @Compony 遠相信美好的事情即將發
*/ */
object ViewModleMain : ViewModel() { object ViewModelMain : ViewModel() {
//悬浮窗口创建 移除 基于无障碍服务 //懸浮視窗建立 移除 基於無障礙服務
var isShowWindow = MutableLiveData<Boolean>() var isShowWindow = MutableLiveData<Boolean>()
//悬浮窗口创建 移除 //懸浮視窗建立 移除
var isShowSuspendWindow = MutableLiveData<Boolean>() var isShowSuspendWindow = MutableLiveData<Boolean>()
//悬浮窗口显示 隐 //懸浮視窗顯示 隱
var isVisible = MutableLiveData<Boolean>() var isVisible = MutableLiveData<Boolean>()
} }

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#ffffff"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z" />
</vector>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#77000000" />
<corners android:radius="18dp" />
</shape>

View File

@ -1,10 +1,32 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:background="@drawable/realtime_clock_background">
<TextView
android:id="@+id/tv_time"
android:layout_width="110dp"
android:layout_height="38dp"
android:gravity="center"
android:letterSpacing="0.1"
android:paddingStart="15dp"
android:text="22:22:22"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
android:layout_width="100dp" android:id="@+id/iv_close"
android:layout_height="100dp" android:layout_width="24dp"
android:src="@drawable/icon_logo" /> android:layout_height="24dp"
</RelativeLayout> android:layout_marginEnd="12dp"
android:src="@drawable/ic_baseline_cancel_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/tv_time"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -9,23 +9,6 @@
android:orientation="vertical" android:orientation="vertical"
android:paddingTop="50dp" android:paddingTop="50dp"
tools:context=".MainActivity"> tools:context=".MainActivity">
<Button
android:id="@+id/bt_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="应用内悬浮窗口(当前页面)" />
<Button
android:id="@+id/bt_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="系统悬浮窗口(全局显示)[锁屏无法显示]" />
<Button
android:id="@+id/bt_04"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="系统悬浮窗口(前台显示)" />
<Button <Button
android:id="@+id/bt_03" android:id="@+id/bt_03"
@ -33,12 +16,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="系统悬浮窗口(全局显示)[无限制]" /> android:text="系统悬浮窗口(全局显示)[无限制]" />
<Button
android:id="@+id/bt_05"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="恢复初始状态" />
<TextView <TextView
android:id="@+id/textView" android:id="@+id/textView"
android:layout_width="match_parent" android:layout_width="match_parent"