將浮動視窗以單例模式生成

This commit is contained in:
Raymond Yang 2023-07-03 15:02:09 +08:00
parent 49fbe33f8d
commit ea629e45a7
6 changed files with 157 additions and 66 deletions

View File

@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.TYPE_APPLICATION_OVERLAY" /> <uses-permission android:name="android.permission.TYPE_APPLICATION_OVERLAY" />
<application <application
android:name=".MyApp"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
@ -17,6 +18,7 @@
tools:targetApi="31"> tools:targetApi="31">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:screenOrientation="landscape"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@ -0,0 +1,69 @@
package com.ray650128.easywindowtest
import android.view.Gravity
import android.view.MotionEvent
import android.view.WindowManager
import com.hjq.window.EasyWindow
object FloatingWindowHelper {
private var _isShowing: Boolean = false
val isShowing: Boolean
get() = _isShowing
private val window by lazy {
EasyWindow<EasyWindow<*>>(MyApp.instance).apply {
setContentView(R.layout.window_hint)
setGravity(Gravity.START or Gravity.TOP)
setYOffset(100)
setImageDrawable(android.R.id.icon, R.drawable.ic_chicken)
setOnTouchListener { window, view, event ->
var touch = false
when (event.action) {
MotionEvent.ACTION_DOWN -> {
window.setWindowFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
)
window.update()
touch = true
}
MotionEvent.ACTION_OUTSIDE -> {
window.setWindowFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
)
window.update()
touch = false
}
else -> {}
}
touch
}
}
}
fun show() {
_isShowing = true
window.show()
}
fun hide() {
_isShowing = false
window.cancel()
}
fun setXOffset(value: Int) {
window.setXOffset(value)
window.update()
}
fun setYOffset(value: Int) {
window.setYOffset(value)
window.update()
}
}

View File

@ -1,6 +1,7 @@
package com.ray650128.easywindowtest package com.ray650128.easywindowtest
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -20,92 +21,63 @@ class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
private val mContext: Context by lazy { this }
private val floatingWindowPermission = registerForActivityResult( private val floatingWindowPermission = registerForActivityResult(
ActivityResultContracts.StartActivityForResult() ActivityResultContracts.StartActivityForResult()
) { result -> ) { result ->
if (result.resultCode == Activity.RESULT_CANCELED) { if (result.resultCode == Activity.RESULT_CANCELED) {
if (!Settings.canDrawOverlays(this)) { if (!Settings.canDrawOverlays(mContext)) {
binding.btnStep1.isEnabled = !Settings.canDrawOverlays(this) binding.btnStep1.isEnabled = !Settings.canDrawOverlays(mContext)
binding.btnStep2.isEnabled = Settings.canDrawOverlays(this) binding.btnStep2.isEnabled = Settings.canDrawOverlays(mContext)
binding.btnStep3.isEnabled = isFloatWindowShowing binding.btnStep3.isEnabled = FloatingWindowHelper.isShowing
return@registerForActivityResult return@registerForActivityResult
} }
showOverlayWindow() showOverlayWindow()
} }
} }
private var isFloatWindowShowing = false
private val window by lazy {
EasyWindow<EasyWindow<*>>(application).apply {
setContentView(R.layout.window_hint)
setGravity(Gravity.START or Gravity.TOP)
setYOffset(100)
setImageDrawable(android.R.id.icon, R.drawable.ic_chicken)
setOnTouchListener { window, view, event ->
var touch = false
when (event.action) {
MotionEvent.ACTION_DOWN -> {
window.setWindowFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
)
window.update()
touch = true
}
MotionEvent.ACTION_OUTSIDE -> {
window.setWindowFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
)
window.update()
touch = false
}
else -> {}
}
touch
}
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
binding.btnStep1.isEnabled = !Settings.canDrawOverlays(this) binding.apply {
binding.btnStep1.setOnClickListener { btnStep1.setOnClickListener {
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
intent.data = Uri.parse("package:$packageName") intent.data = Uri.parse("package:$packageName")
floatingWindowPermission.launch(intent) floatingWindowPermission.launch(intent)
} }
binding.btnStep2.isEnabled = Settings.canDrawOverlays(this) btnStep2.setOnClickListener {
binding.btnStep2.setOnClickListener { showOverlayWindow()
showOverlayWindow() }
}
binding.btnStep3.isEnabled = isFloatWindowShowing btnStep3.setOnClickListener {
binding.btnStep3.setOnClickListener { hideOverlayWindow()
hideOverlayWindow() }
}
}
override fun onResume() {
super.onResume()
binding.apply {
btnStep1.isEnabled = !Settings.canDrawOverlays(mContext)
btnStep2.isEnabled = Settings.canDrawOverlays(mContext) && !FloatingWindowHelper.isShowing
btnStep3.isEnabled = FloatingWindowHelper.isShowing
} }
} }
private fun showOverlayWindow() { private fun showOverlayWindow() {
isFloatWindowShowing = true FloatingWindowHelper.show()
binding.btnStep2.isEnabled = !isFloatWindowShowing binding.btnStep2.isEnabled = !FloatingWindowHelper.isShowing
binding.btnStep3.isEnabled = isFloatWindowShowing binding.btnStep3.isEnabled = FloatingWindowHelper.isShowing
window.show()
} }
private fun hideOverlayWindow() { private fun hideOverlayWindow() {
isFloatWindowShowing = false FloatingWindowHelper.hide()
binding.btnStep2.isEnabled = !isFloatWindowShowing binding.btnStep2.isEnabled = !FloatingWindowHelper.isShowing
binding.btnStep3.isEnabled = isFloatWindowShowing binding.btnStep3.isEnabled = FloatingWindowHelper.isShowing
window.cancel()
} }
} }

View File

@ -0,0 +1,21 @@
package com.ray650128.easywindowtest
import android.app.Application
import android.content.Context
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
private val TAG = MyApp::class.java.simpleName
var instance: Application? = null
val appContext: Context
get() = instance!!.applicationContext
}
}

View File

@ -6,21 +6,39 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity"> tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一步:請先允許懸浮窗權限"
app:layout_constraintBottom_toTopOf="@+id/btnStep1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button <Button
android:id="@+id/btnStep1" android:id="@+id/btnStep1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="第一步,開啟懸浮窗權限" android:text="授予懸浮窗權限"
app:layout_constraintBottom_toTopOf="@+id/btnStep2" app:layout_constraintBottom_toTopOf="@+id/btnStep2"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第二步:開啟懸浮窗"
app:layout_constraintBottom_toTopOf="@+id/btnStep2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button <Button
android:id="@+id/btnStep2" android:id="@+id/btnStep2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="第二步,啟動懸浮窗" android:text="啟動懸浮窗"
app:layout_constraintBottom_toTopOf="@+id/btnStep3" app:layout_constraintBottom_toTopOf="@+id/btnStep3"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -36,4 +54,13 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnStep2" /> app:layout_constraintTop_toBottomOf="@+id/btnStep2" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="若想關閉懸浮窗,按一下:"
app:layout_constraintBottom_toTopOf="@+id/btnStep3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,3 +1,3 @@
<resources> <resources>
<string name="app_name">EasyWindowTest</string> <string name="app_name">懸浮視窗 by 楓小夜</string>
</resources> </resources>