Skip to content

Commit

Permalink
miui home: swipe and hover recent task to force stop
Browse files Browse the repository at this point in the history
  • Loading branch information
5ec1cff committed Dec 30, 2024
1 parent 36e0e73 commit 1024d20
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 0 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ com.android.systemui

- 长按通知时在屏幕顶端显示该通知的详细信息,如通知渠道、id、pid、时间等,点按可以进入对应通知渠道的设置页面

### 小米桌面

```
com.miui.home
```

- 最近任务卡片划动时悬停 700ms
后再划动即可杀死进程(「清理任务」字样替换为「停止进程」,不会阻止系统的划卡杀,需要配合其他划卡杀白名单模块使用,如 [NoSwipeToKill](https://github.com/dantmnf/NoSwipeToKill)

## 过期功能

长期未维护,可能不可用
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/five/ec1cff/myinjector/Entry.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Entry : IXposedHookLoadPackage, IXposedHookZygoteInit {
"com.zhihu.android" -> ZhihuXposedHandler()
"com.android.chrome", "com.kiwibrowser.browser" -> ChromeHandler()
"com.baidu.input" -> BaiduIMEHandler()
"com.miui.home" -> MiuiHomeHandler()
else -> return
}
handler.handleLoadPackage(lpparam)
Expand Down
132 changes: 132 additions & 0 deletions app/src/main/java/five/ec1cff/myinjector/MiuiHomeHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package five.ec1cff.myinjector

import android.app.IActivityManager
import android.content.ComponentName
import android.os.Handler
import android.os.Looper
import android.os.ServiceManager
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage

class MiuiHomeHandler : IXposedHookLoadPackage {
companion object {
private const val TAG = "MyInjector-MIUIHomeHandler"
}

override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
Log.d(TAG, "handleLoadPackage: hooked")
runCatching {
val recentTouchHandlerClass = XposedHelpers.findClass(
"com.miui.home.recents.views.TaskStackViewTouchHandler", lpparam.classLoader
)

XposedBridge.hookAllMethods(
recentTouchHandlerClass,
"onBeginDrag",
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
onBeginDrag(param.args[0] as View)
}
})

XposedBridge.hookAllMethods(
recentTouchHandlerClass,
"onDragEnd",
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
onDragEnd(param.args[0] as View)
}
})

XposedBridge.hookAllMethods(
recentTouchHandlerClass,
"onChildDismissedEnd",
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
onChildDismissedEnd(param.args[0] as View)
}
})

XposedBridge.hookAllMethods(
recentTouchHandlerClass,
"onDragCancelled",
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
onDragCancelled(param.args[0] as View)
}
})
}.onFailure {
Log.e(TAG, "handleLoadPackage: ", it)
}
}

private var handler = Handler(Looper.getMainLooper())
private var mCurrentView: View? = null
private var origText: CharSequence? = null
private var setViewHeaderRunnable = Runnable { setupToBeKilled() }
private var mToBeKilled: View? = null
private val ams by lazy { IActivityManager.Stub.asInterface(ServiceManager.getService("activity")) }

private fun findDismissView(): TextView {
val v = XposedHelpers.getObjectField(mCurrentView, "mHeaderView")
return XposedHelpers.getObjectField(v, "mDismissView") as TextView
}

private fun setupToBeKilled() {
mCurrentView ?: return
findDismissView().text = "停止进程"
mToBeKilled = mCurrentView
}

private fun onBeginDrag(v: View) {
mCurrentView = v
mToBeKilled = null
origText = findDismissView().text
handler.postDelayed(setViewHeaderRunnable, 700)
}

private fun onDragEnd(v: View) {
handler.removeCallbacks(setViewHeaderRunnable)
if (origText != null) findDismissView().text = origText
mCurrentView = null
origText = null
}

private fun onDragCancelled(v: View) {
Log.d(TAG, "onDragCancelled: cancelled $mToBeKilled")
mToBeKilled = null
}

private fun onChildDismissedEnd(v: View) {
if (mToBeKilled != v) {
Log.e(TAG, "onChildDismissedEnd: not target: $v $mToBeKilled")
return
}
mToBeKilled = null
val task = XposedHelpers.getObjectField(v, "mTask")
val key = XposedHelpers.getObjectField(task, "key")
val user = XposedHelpers.getObjectField(key, "userId") as Int
val topActivity = XposedHelpers.getObjectField(key, "topActivity") as ComponentName
runCatching { ams.forceStopPackage(topActivity.packageName, user) }
.onSuccess {
Toast.makeText(v.context, "killed ${topActivity.packageName}", Toast.LENGTH_SHORT)
.show()
}
.onFailure {
Toast.makeText(
v.context,
"killed ${topActivity.packageName} failed",
Toast.LENGTH_SHORT
)
.show()
Log.e(TAG, "onChildDismissedEnd: ", it)
}
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
<item>com.android.chrome</item>
<item>com.kiwibrowser.browser</item>
<item>com.baidu.input</item>
<item>com.miui.home</item>
</string-array>
</resources>
13 changes: 13 additions & 0 deletions hidden-api/src/main/java/android/app/IActivityManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package android.app;

import android.os.IBinder;

public interface IActivityManager {
void forceStopPackage(String packageName, int userId);

class Stub {
public static IActivityManager asInterface(IBinder binder) {
throw new UnsupportedOperationException("");
}
}
}

0 comments on commit 1024d20

Please sign in to comment.