我一直致力于创建一个 Android 应用程序,该应用程序可以每 5 秒在屏幕上执行一次向上滑动手势。这个想法是让它滚动任何打开的应用程序,例如 Instagram 上的 reels、Facebook 时间线或 Pintrest。
我已确保为应用程序提供所需的所有权限,正确设置 Android 清单,并配置辅助功能服务。我还整理了我认为 GestureAccessibilityService 类的正确代码。
但它没有做它应该做的事情。我一直在试图找出代码有什么问题。请帮忙。
accessibility_service_config.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:canRequestTouchExplorationMode="true"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:accessibilityEventTypes="typeAllMask"
android:canRetrieveWindowContent="true"
android:notificationTimeout="100"/>
Android 清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ThumbD"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ScrollAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name=".ScrollAccessibilityService"
android:resource="@xml/accessibility_service_config"/>
</service>
</application>
</manifest>
GestureAccessibilityService.kt
class GestureAccessibilityService:AccessibilityService() {
private val TAG = "GESTURE"
private val handler = Handler(Looper.getMainLooper())
private val gestureRunnable = object : Runnable {
override fun run() {
performSwipeUp()
//dispatch(0f,0f,0f,200f, applicationContext)
handler.postDelayed(this, 5000) // Repeat every 5 seconds (5000 milliseconds)
}
}
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
}
override fun onInterrupt() {
// NO-OP
}
override fun onServiceConnected() {
super.onServiceConnected()
"onServiceConnected".logd()
handler.postDelayed(gestureRunnable, 0)
}
override fun onDestroy() {
super.onDestroy()
// Stop the repeating gesture when the service is destroyed
handler.removeCallbacks(gestureRunnable)
}
private fun performSwipeUp() {
val displayMetrics = resources.displayMetrics
val screenHeight = displayMetrics.heightPixels
val gestureDescription = GestureDescription.Builder()
.addStroke(
GestureDescription.StrokeDescription(
Path().apply {
moveTo(displayMetrics.widthPixels / 2f, screenHeight * 0.8f)
lineTo(displayMetrics.widthPixels / 2f, screenHeight * 0.2f)
},
0,
500
)
)
.build()
val result = dispatchGesture(gestureDescription, object : GestureResultCallback() {
override fun onCompleted(gestureDescription: GestureDescription?) {
super.onCompleted(gestureDescription)
"Gesture completed".logd()
}
override fun onCancelled(gestureDescription: GestureDescription?) {
super.onCancelled(gestureDescription)
"Gesture cancelled".logd()
}
}, null)
"STATUS $result".logd()
}
fun dispatch(x: Float, y: Float,xx: Float, yy: Float, context:Context): Boolean {
try {
val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
val isEnabled = accessibilityManager.isEnabled
if (isEnabled) {
val result = dispatchGesture(
buildSwipe(x, y, xx, yy),
object : GestureResultCallback() {
override fun onCompleted(gestureDescription: GestureDescription?) {
super.onCompleted(gestureDescription)
"Gesture completed".logd()
}
override fun onCancelled(gestureDescription: GestureDescription?) {
super.onCancelled(gestureDescription)
"Gesture cancelled".logd()
}
},
null
)
"STATUS $result".logd()
return result
} else {
// Accessibility service is not enabled
return false
}
}catch (e: Exception) {
"Error dispatching gesture: ${e.message}".logd()
e.printStackTrace()
return false
}
}
private fun buildSwipe(
startX: Float,
startY: Float,
endX: Float,
endY: Float
): GestureDescription {
val swipePath = Path()
swipePath.apply {
moveTo(startX, startY)
lineTo(endX, endY)
}
val swipeBuilder = GestureDescription.Builder()
swipeBuilder.addStroke(GestureDescription.StrokeDescription(swipePath, 0, 100L))
return swipeBuilder.build()
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
/*Permissions*/
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
listOf(
Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE,
Manifest.permission.BIND_ACCESSIBILITY_SERVICE
)
} else {
listOf(Manifest.permission.BIND_ACCESSIBILITY_SERVICE)
}
checkPermissions(permissions)
if(isAccessibilityServiceEnabled(this)){
"started sevices------->".logd()
}
}
fun permissionAccessServices(view: View){
openAccessibilitySettings(this)
}
private fun checkPermissions(permissions: List<String>){
PermissionX.init(this)
.permissions(permissions)
.request { allGranted, grantedList, deniedList ->
if (allGranted) {
Log.d("Permission","SuccessFull");
} else {
Log.d("Permission","Failed $deniedList");
}
}
}
private fun isAccessibilityServiceEnabled(mContext: Context): Boolean {
var accessibilityEnabled = 0
val service: String = mContext.packageName + "/" + GestureAccessibilityService::class.java.canonicalName
try {
accessibilityEnabled = Settings.Secure.getInt(
mContext.applicationContext.contentResolver,
Settings.Secure.ACCESSIBILITY_ENABLED
)
"accessibilityEnabled = $accessibilityEnabled".logd()
} catch (e: Settings.SettingNotFoundException) {
"Error finding setting, default accessibility to not found: ${e.message}".logd()
}
val mStringColonSplitter = TextUtils.SimpleStringSplitter(':')
if (accessibilityEnabled == 1) {
"Accessibility Is Enabled".logd()
val settingValue: String = Settings.Secure.getString(
mContext.applicationContext.contentResolver,
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
)
if (settingValue != null) {
mStringColonSplitter.setString(settingValue)
while (mStringColonSplitter.hasNext()) {
val accessibilityService = mStringColonSplitter.next()
"AccessibilityService :: $accessibilityService $service".logd()
if (accessibilityService.equals(service, ignoreCase = true)) {
"accessibility is switched on!".logd()
return true
}
}
}
} else {
"accessibility is disabled".logd()
}
return false
}
}
因此,Android Manifest 中存在错误。元标记的值不正确。如果有人想要创建自动滚动器,他们只需复制上面提供的代码并将以下代码片段添加到他们的 Android 清单中即可。通过此调整,他们将拥有一个能够在任何应用程序上执行手势的功能应用程序。
<service
android:name=".GestureAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="specialUse"
android:process=":AccessibilityService">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
<-- android:name=".GestureAccessibilityService" -->
android:name="android.accessibilityservice" // this is correct
android:resource="@xml/accessibility_service_config"/>
</service>