11package com.xposed.miuiime
22
3+ import android.content.IntentFilter
34import android.view.inputmethod.InputMethodManager
45import com.github.kyuubiran.ezxhelper.init.EzXHelperInit
56import com.github.kyuubiran.ezxhelper.utils.Log
67import com.github.kyuubiran.ezxhelper.utils.findMethod
78import com.github.kyuubiran.ezxhelper.utils.getObjectAs
89import com.github.kyuubiran.ezxhelper.utils.getStaticObject
910import com.github.kyuubiran.ezxhelper.utils.hookAfter
11+ import com.github.kyuubiran.ezxhelper.utils.hookBefore
1012import com.github.kyuubiran.ezxhelper.utils.hookReplace
1113import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant
14+ import com.github.kyuubiran.ezxhelper.utils.invokeMethodAs
1215import com.github.kyuubiran.ezxhelper.utils.invokeStaticMethodAuto
1316import com.github.kyuubiran.ezxhelper.utils.loadClassOrNull
1417import com.github.kyuubiran.ezxhelper.utils.putStaticObject
@@ -28,16 +31,21 @@ class MainHook : IXposedHookLoadPackage {
2831 private var navBarColor: Int? = null
2932
3033 override fun handleLoadPackage (lpparam : XC_LoadPackage .LoadPackageParam ) {
31- // 检查是否支持全面屏优化
34+ // 检查是否支持全面屏优化
3235 if (PropertyUtils [" ro.miui.support_miui_ime_bottom" , " 0" ] != " 1" ) return
3336 EzXHelperInit .initHandleLoadPackage(lpparam)
3437 EzXHelperInit .setLogTag(TAG )
3538 Log .i(" miuiime is supported" )
36- startHook(lpparam)
39+
40+ if (lpparam.packageName == " android" ) {
41+ startPermissionHook()
42+ } else {
43+ startHook(lpparam)
44+ }
3745 }
3846
3947 private fun startHook (lpparam : XC_LoadPackage .LoadPackageParam ) {
40- // 检查是否为小米定制输入法
48+ // 检查是否为小米定制输入法
4149 val isNonCustomize = ! miuiImeList.contains(lpparam.packageName)
4250 if (isNonCustomize) {
4351 val sInputMethodServiceInjector =
@@ -56,7 +64,7 @@ class MainHook : IXposedHookLoadPackage {
5664 lpparam.classLoader
5765 )
5866
59- // 获取常用语的ClassLoader
67+ // 获取常用语的ClassLoader
6068 findMethod(" android.inputmethodservice.InputMethodModuleManager" ) {
6169 name == " loadDex" && parameterTypes.sameAs(ClassLoader ::class .java, String ::class .java)
6270 }.hookAfter { param ->
@@ -73,8 +81,8 @@ class MainHook : IXposedHookLoadPackage {
7381 hookIsXiaoAiEnable(it)
7482 }
7583
76- // 针对A11的修复切换输入法列表
77- it.getMethod (" getSupportIme" ).hookReplace { _ ->
84+ // 针对A11的修复切换输入法列表
85+ it.getDeclaredMethod (" getSupportIme" ).hookReplace { _ ->
7886 it.getStaticObject(" sBottomViewHelper" )
7987 .getObjectAs<InputMethodManager >(" mImm" ).enabledInputMethodList
8088 }
@@ -94,7 +102,7 @@ class MainHook : IXposedHookLoadPackage {
94102 clazz.putStaticObject(" sIsImeSupport" , 1 )
95103 Log .i(" Success:Hook field sIsImeSupport" )
96104 }.onFailure {
97- Log .i(" Failed:Hook field sIsImeSupport " )
105+ Log .i(" Failed:Hook field sIsImeSupport" )
98106 Log .i(it)
99107 }
100108 }
@@ -169,4 +177,52 @@ class MainHook : IXposedHookLoadPackage {
169177 Log .i(it)
170178 }
171179 }
180+
181+ /* *
182+ * Hook 获取应用列表权限,为所有输入法强制提供获取输入法列表的权限。
183+ * 用于修复部分输入法(搜狗输入法小米版等)缺少获取输入法列表权限,导致切换输入法功能不能显示其他输入法的问题。
184+ * 理论等效于在输入法的AndroidManifest.xml中添加:
185+ * ```xml
186+ * <manifest>
187+ * <queries>
188+ * <intent>
189+ * <action android:name="android.view.InputMethod" />
190+ * </intent>
191+ * </queries>
192+ * </manifest>
193+ * ```
194+ * 当前实现可能影响开机速度,如需此修复需手动设置系统框架作用域。
195+ */
196+ private fun startPermissionHook () {
197+ runCatching {
198+ findMethod(" com.android.server.pm.AppsFilterUtils" ) {
199+ name == " canQueryViaComponents"
200+ }.hookAfter { param ->
201+ if (param.result == true ) return @hookAfter
202+ val querying = param.args[0 ]
203+ val potentialTarget = param.args[1 ]
204+ if (! isIme(querying)) return @hookAfter
205+ if (! isIme(potentialTarget)) return @hookAfter
206+ param.result = true
207+ }
208+ }.onFailure {
209+ Log .i(" Failed: Hook method canQueryViaComponents" )
210+ Log .i(it)
211+ }
212+ }
213+
214+ private fun isIme (androidPackage : Any ): Boolean {
215+ val services = androidPackage.invokeMethodAs<List <Any >>(" getServices" )
216+ services?.forEach { service ->
217+ if (! service.invokeMethodAs<Boolean >(" isExported" )!! ) return @forEach
218+ val intents = service.invokeMethodAs<List <Any >>(" getIntents" )
219+ intents?.forEach { intent ->
220+ val intentFilter = intent.invokeMethodAs<IntentFilter >(" getIntentFilter" )
221+ if (intentFilter?.matchAction(" android.view.InputMethod" ) == true ) {
222+ return true
223+ }
224+ }
225+ }
226+ return false
227+ }
172228}
0 commit comments