Appearance

安卓状态栏 系统图标 隐藏输入法(搜狗)图标

问题描述

使用搜狗输入法时,手机顶部状态栏的右侧图标会出现一个搜狗输入法的图标。希望能将其关闭。 alt text

思考方向

  • 可能是系统单独做了适配,在识别到搜狗输入法启动时在右上角显示图标。
  • 这个图标也可能是在输入法apk自身存着的,所以可以看看apk的资源文件。
  • 尝试搜索引擎搜索关键词:安卓状态栏 右侧图标

探究过程

系统层面

搜到了一个自定义图标的 Android状态栏右侧添加图标并控制其显示状态open in new window。里面提到了一个xml可以配置图标
在frameworks/base/core/res/res/values/config.xml的string-array name="config_statusBarIcons"中添加我们自己的slot。比如:
<item><xliff:g id="id">@string/status_bar_input_type</xliff:g></item>

后续是发送广播和接收广播,但是dex中并没有搜到相关广播和intent。


又搜到了一个文章Android系统状态栏定制open in new window,这里提到了状态栏中图标的分布规则如图,也就是说输入法的图标应该属于系统icon。 alt text

后续提到了几个java类,StatusBarIconHolder, Slot 等,在dex中还是搜不到。只搜StatusBar倒是能搜到很多,但都是获取状态栏颜色,高度等,没有设置图标相关。


又搜到了一个文章Android IME输入法启动&显示&隐藏流程梳理以及常见问题&调试技巧小结open in new window

太长了,直接搜status,发现了这样一句

public class InputMethodManagerService extends IInputMethodManager.Stub
        implements ServiceConnection, Handler.Callback {
        public InputMethodManagerService(Context context) {
            .....
            // 状态栏输入法图标名称, 会根据这个名称设置输入法的图标显示
            mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
            ......
            }
    ......
        }

也就是说获取这个id的字符串时,系统会自动向当前正在使用的输入法请求获取其名称?图标是从输入法app中获取,而非存在系统图标库中?(后面研究发现这里应该是我理解错了)


尝试搜索com.android.internal.R.string.status_bar_ime相关信息。
搜到一篇文章Android SystemUI 状态栏——系统状态图标显示与管理open in new window,又提到了framework/base/core/res/res/values/config.xml。仔细看了一下,发现确实有status_bar_ime的定义。

alt text

突然想到,之前用AndroidKiller的时候,提到过一个framework.jar的东西,我的理解是这里面存着系统预设的一些样式和图标资源等文件,不如直接找到这个文件,去看一下图标在不在里面。

打开vmos进入根目录,很轻松发现了/system/framework/目录下有一个41M的apk,名字叫framework-res.apk。打开arsc一瞧,果然status_bar_ime在一个array里面。

alt text

但是再仔细一瞧,array里记录的是资源id的id,下面还有一个string类型的资源id的status_bar_ime,其对应实际字符串就是"ime"三个字母。所以我上面理解的有误,mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime); 这个获取到的应该是ime三个字母,然后猜测后续操作是把这个作为key,去一个map中寻找它对应的图标。


在上面的文章中,发现了一个单词,叫SystemUI。于是换个关键词再继续搜索。

发现了这样一篇文章Android隐藏输入法图标方法——为SystemUI状态栏定制open in new window(还有https://blog.csdn.net/baidu_41666295/article/details/126802001)

bing的搜索结果预览看上去非常美好,甚至直接提到了搜狗输入法。

alt text

结果点击去csdn告诉我要花60块钱订阅。。。。搜了一下标题和这段预览文字,也没能找到免费版。(吐槽一下csdn,最近越来越多付费文章了,甚至零几年的文章都变成付费,点开作者头像一看好久没发过文章,很是怀疑csdn看哪篇文章浏览量高直接自动变成付费的,就像csdn下载文件一样)


继续翻阅搜索结果,又找到一篇文章Android 10 SystemUI 如何隐藏状态栏输入法图标open in new window 这篇文章非常简洁明了,做法是修改InputMethodManagerService.updateStatusIcon函数。 代码路径: frameworks/base/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java 在InputMethodManagerService.java文件中updateStatusIcon方法中将mStatusBar.setIconVisibility(mSlotIme, true)的true改为false

看起来非常简单,但不太符合我的需求,因为用户一般没法自己改这种底层代码然后再自己编译。


根据那篇付费文章启发,搜索引擎搜素关键词直接写上搜狗输入法,这次搜到了一篇文章:安卓隐藏搜狗输入法右上角图标open in new window

更加简洁明了,adb shell settings put secure icon_blacklist ime 搞定。看样子是用adb权限修改系统设置,禁用了系统图标中的输入法图标的显示。也就是说以后不管用什么输入法右上角都不会再显示图标了。这个方法还可以。

应用层面

问题已经可以解决了,用adb进行全局设置即可。但是有没有别的解决方案呢?既然只有搜狗显示,别的不显示,而且图标也是存在app自身而非系统内,那么这个图标设置一定是在搜狗输入法的代码里完成的。

定位代码的思路:

  1. 既然是从app传过去的图标,那在apk/res/drawable这种目录下一定能找到图标,然后dex里搜它资源id就行了
  2. 修改系统代码虽然不太可行,但是提供了关键词可以用来搜索:InputMethodManagerService
  3. 如果不是在dex中设置,也可能是在manifest中声明,比如在meta-data里记录图标的资源id,然后系统直接从这读取。

第一种方案尝试了一下就放弃了,因为res下的文件名都是随机字母,还分了无数个子文件夹,这要我找到天荒地老啊(找了一会找到了48x48和60x60的看起来很像的图标,但是dex中没有id调用)。

第三种方案也搜过了,看了所有带meta-datastatus的地方,没有状态栏右上角的那个图标。

万般无奈之下只好搜索InputMethodManagerService,(这种一看就是系统层的代码,然后对用户隐藏的,sdk中搜不到,所以想要定位函数或者找函数调用啥的很麻烦。)
好在搜到了一篇文章: android开发浅谈之InputMethodManagerServiceopen in new window

alt text

我们自己实现输入法,需要继承InputMethodService类,然后InputMethodManager在sdk中也是可见的,只有InputMethodManagerService不可见。

先整理一下思路。

  • 直接改InputMethodManagerService.updateStatusIcon做不到,但是可以做到不调用updateStatusIcon,或者保留调用这个函数但是尝试往里传一个不存在的资源id。因此就要寻找都有哪些地方调用了updateStatusIcon这个函数。
  • 由于这个函数所在类在sdk中找不到,所以想要查找函数调用很不方便。

现在需要解决的问题就是:如何查找updateStatusIcon的函数调用。根据上面的图可以发现,这三个类都是紧密相连的,也就是说互相之间都有沟通,那么就可以去另外两个可见类中,搜索是否有对updateStatusIcon的调用。

InputMethodManager里搜索updateStatusIcon,还真出现了,在InputMethodManager.showStatusIcon函数中,根据名字一眼就能明白,调用此函数后,状态栏右侧就会显示输入法图标。但是这个函数被注明废弃,说应该用InputMethodService.showStatusIcon(int)

不管哪个都好,直接去dex里搜showStatusIcon,发现只有一处调用

alt text

注释掉之后,发现果然状态栏不再显示输入法的系统图标了。左图修改前,右图修改后:

alt text

当然,修改apk带来的代价就是:每次启动都会有个Toast:你使用的是盗版应用。不确定后续使用中是否还有其他副作用。

总结

  • SystemUI:负责系统UI绘制,例如状态栏(顶端),导航栏(底端),通知栏(状态栏下拉)等等。
  • 输入法图标所在的位置,对应的是状态栏右侧的系统图标区域,与左侧的应用通知图标稍有不同。
  • 可以在应用中调用InputMethodService.show/hideStatusBar(int),来显示/隐藏输入法对应的系统图标,也可以使用adb shell settings put secure icon_blacklist ime借助adb禁用输入法系统图标。
  • 上面贴的文章中,有一些还介绍了输入法的adb调试相关,例如
    # 列出所有输入法服务
    adb shell ime list -a -s
    # 可以获取到输入法的各种信息, 并且可以过滤window信息
    adb shell dumpsys input_method | grep -i window
    # 获取输入法的窗口状态信息
    adb shell dumpsys window | grep -i input
    
Last Updated 3/22/2024, 7:23:32 AM