Android的所有系统设置项(如音量、触摸提示音、默认输入法等信息)均是保存到一个数据库。在界面上调整设置时将值保存到该数据库,开机时将从数据库读取值作为默认设置。这些读取、设置操作都可以通过API或adb命令进行。
P.S.本文仅作为学习记录,知识点、代码上下文并不完整与正确,以后再改善吧。

需求

机顶盒项目要求Android系统开机后默认启用指定的触宝输入法;默认关闭触摸声、锁屏声、电源充电声。
之前的做法似乎是修改固件实现,但由于早期固件已经用于生产,后续的OTA升级没有办法使修改生效,就导致无法对早期盒子方便地进行默认设置(除非烧写固件),因此考虑从应用层实现,因而有了本次实践。

Settings类API

系统设置主要使用的API位于android.provider.Settings,来看看Settings类的结构:

该类定义了许多常量,实际上就是每个设置项在数据库中的字段名;此外还有修改数据的put方法与读取的get方法。
需要着重注意的是,这些常量被细分到了System、Secure、Global三个内部类中,对应三种不同的权限或者说作用范围,在修改不同内部类的属性时,需调用对应内部类的put方法方能生效。

禁用触摸声的常量定义属于Settings.System范围,设置禁用的方法为:

String key = Settings.System.SOUND_EFFECTS_ENABLED;//"sound_effects_enabled"
int value = 0;//0禁用 1启用
boolean success = Settings.System.putInt(mContext.getContentResolver(), key, value);

再如,默认输入法常量定义属于Settings.Secure范围,设置方法为:
(注意此处putString()方法是Secure内部类的方法)

String key = Settings.Secure.DEFAULT_INPUT_METHOD;//"default_input_method"
String id = "com.android.inputmethod.latin/.LatinIME";//Android默认输入法ID
boolean success = Settings.Secure.putString(mContext.getContentResolver(), key, id);

为什么要强调使用的内部类呢?因为System、Secure、Global三个内部类都有同样的put、get方法,方法参数又只是String类型的键值,因此很容易用错方法。通过源码知道,当调用方法和常量不属于同一内部类时,最终会设置失败(返回值为false)。比如,System.putInt()最后会调用System.putStringForUser()进行处理,如果常量属于Secure或Global范围,将直接返回false而不会进行存储。

/** @hide */
public static boolean putStringForUser(ContentResolver resolver, String name, String value,int userHandle) {if (MOVED_TO_SECURE.contains(name)) {Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"+ " to android.provider.Settings.Secure, value is unchanged.");return false;}if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"+ " to android.provider.Settings.Global, value is unchanged.");return false;}return sNameValueCache.putStringForUser(resolver, name, value, userHandle);
}

Settings数据库

(本节所述均为个人的理解,时间关系没有去确认,如果误导请包涵和指正)
上节所做的设置,最后都被保存到系统数据库中,(不知道称其为数据库还是ContentProvider比较准确),系统在开机时读取这些值进行默认的设置。
Settings实际上是一个apk,负责所有系统级别属性的设置。我司正在Realtek芯片上做产品,Realtek就提供了他们包装的Settings作为demo供我们调试,从Settings的源码中可以看到很多定制的功能。

Settings数据库的位置位于

adb shell
cd /data/data/com.android.providers.settings/databases
- settings.db-backup
- settings.db-journal

将settings.db-backup改名为settings.db,即可使用sqlite工具查看,如下:

可以看到,该数据库中有三个表system、secure、global对应API中的定义的常量,此处触摸声”sound_effects_enabled”位于system表中,当前状态为0。

以上是我个人的推测,因为该数据库中并不存在默认输入法的字段常量“default_input_method”(然而却可以生效)。从文件名“settings.db-backup”可以知道,这并不是系统的实时数据,而仅是备份数据。并且,对于系统的设置的变更,该数据库也并没有实时改变,也验证了这一点。Settings设置的实时数据被存储到哪里,我目前没有找到,但八九不离十,由于并不影响功能实现,就暂且搁置。

P.S.此处也可以看到realtek关键字,可见不同的平台厂商对android有不同的定制,需要对症下药。

ADB修改数据库

除了调用android.provider.Settings的API来修改系统设置外,在开发阶段还可以使用adb命令方便地修改Settings数据库,并且界面上是立即生效的哦(视厂商刷新机制而定)。如,关闭触摸声、设置默认输入法,可以用以下adb命令立即生效(仍然需要注意区别system/secure/global):

settings put system sound_effects_enabled 0
settings put secure default_input_method com.android.inputmethod.latin/.LatinIME

可以用ADB命令来确认要修改的键值对。

设置默认输入法

有了上述的背景知识,就可以轻松地设置系统的默认输入法了。

代码

这里从工程中抽出了设置默认输入法的代码,可能并不完整,但思路很清晰了:

    import android.provider.Settings;//导入包/*** 若触宝输入法已安装,则设其为系统默认输入法* (写入Android系统数据库)*/public static void setDefaultInputMethod(Context context){//获取系统已安装的输入法IDString[] methods = getInputMethodIdList(context);if (methods == null || methods.length == 0){EvLog.w(String.format("found no input method."));return;}//检查是否安装触宝输入法//触宝输入法ID "com.cootek.smartinputv5/com.cootek.smartinput5.TouchPalIME";String targetKeyword = "TouchPal";String value = "";for (String m : methods){EvLog.d(String.format("find : %s", m));if (m.toLowerCase().contains(targetKeyword.toLowerCase())){value = m;//找到触宝输入法}}if (value == "") {EvLog.w(String.format("didn't find " + targetKeyword));return;}//设置默认输入法String key = Settings.Secure.DEFAULT_INPUT_METHOD;boolean success = Settings.Secure.putString(context.getContentResolver(), key, value);EvLog.d(String.format("writeDbDefaultInputMethod(%s),result: %s", value,success));//读取默认输入法String current = Settings.Secure.getString(context.getContentResolver(),key);EvLog.d(String.format("current default: %s",current));      }/*** 获取系统已安装的输入法ID* @param context* @return*/public static String[] getInputMethodIdList(Context context){InputMethodManager imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);if (imm != null && imm.getInputMethodList() != null){String[] methodIds = new String[imm.getInputMethodList().size()];for (int i = 0; i <imm.getInputMethodList().size(); i++) {methodIds[i] = imm.getInputMethodList().get(i).getId();}return methodIds;}return new String[]{};}

输入法ID

设置Settings.Secure.DEFAULT_INPUT_METHOD的值时需要输入法的ID:

/*** Setting to record the input method used by default, holding the ID* of the desired method.*/
public static final String DEFAULT_INPUT_METHOD = "default_input_method";

输入法ID形式如:

com.android.inputmethod.latin/.LatinIME (缩写)
com.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME (完整)
com.sohu.inputmethod.sogou.xiaomi/.SogouIME (搜狗输入法小米版)

LatinIME是android自带输入法,斜杠/后的点.表示相同包名的缩写形式,但当IME的路径与包名并不完全相同时不能使用缩写形式,如触宝输入法: (注意到inputv5与input5的区别)

com.cootek.smartinputv5/com.cootek.smartinput5.TouchPalIME

不能缩写为

com.cootek.smartinputv5/.TouchPalIME (前缀不同,不能缩写)

getInputMethodIdList()方法展示了如何获取系统已安装的输入法ID。一开始因为同事提供了错误的触宝输入法ID缩写形式,导致设置默认输入法后,无法开启任何输入法(因为不存在上述缩写形式表示的输入法)。于是我通过getInputMethodIdList()获取系统安装的输入法ID,并通过关键字来确定要设置的输入法。
问题解决。

关联问题

接触到Settings类后,想起来以前处理的一个问题:通过定制的API修改系统分辨率后,重启后并不生效。
原因是在修改分辨率后,还要往Settings数据库中写入新的分辨率配置,否则,重启开机会根据Settings中的数据进行恢复。

Android.Settings类设置默认输入法相关推荐

  1. android 程序中设置默认输入法

    String key = Settings.Secure.DEFAULT_INPUT_METHOD;//"default_input_method" String id = &qu ...

  2. Android设置默认输入法

    先安装想要设置默认的输入法 获取系统已安装的输入法ID /*** 获取系统已安装的输入法ID** @param context* @return*/public static String[] get ...

  3. android 设置默认输入法

    设置默认输入法 在 frameworks/base/core/res/res/values/config.xml 添加一个属性: <!--leo add--> <string nam ...

  4. android9.0设置默认输入法

    1.设置默认输入法 amlogic_t972/frameworks/base/services$ git diff core/java/com/android/server/InputMethodMa ...

  5. Android源码配置默认输入法

    文章目录 Android源码定制默认输入法 声明 Android源码修改默认输入法 关于配置默认输入法的包名和类名 修改说明 Android源码定制默认输入法 声明 郑重声明:博文为原创内容,可以转载 ...

  6. 设置默认输入法及输入法相关设置

    测试平台 Platform: RK3399 OS: Android 7.1.1 需求 始终弹出软键盘 设置默认输入法 解决方案 始终弹出软键盘 : 系统默认当连接物理键盘时,虚拟键盘不会弹出. dif ...

  7. Android替换/修改系统默认输入法

    各大输入法的服务 ro.mtk_default_ime=com.tencent.qqpinyin.QQPYInputMethodService//默认qq输入法 ro.mtk_default_ime= ...

  8. [RK3399][Android7.1.1]Android->输入法:设置默认输入法及输入法相关设置

    测试平台 Platform: RK3399 OS: Android 7.1.1 需求 始终弹出软键盘 设置默认输入法 解决方案 1. 始终弹出软键盘 : 系统默认当连接物理键盘时,虚拟键盘不会弹出. ...

  9. 20111228_给窗体设置默认输入法

    //给窗体设置默认输入法 //新建一个窗体类ImeForm,设置Form1:ImeForm public class ImeForm:System.Windows.Forms.Form { [DllI ...

最新文章

  1. micropython stm32f103_micropython
  2. python执行代码加key_用Python在注册表运行键中创建新值?
  3. 2410Init.s
  4. C++的三种容器适配器
  5. ubuntu14.04 下emacs 24 配置
  6. 如何高效的将 DataReader 转成 ListT ?
  7. (第2篇)一篇文章教你轻松安装hadoop
  8. 使用while和FOR循环分布打印字符串S='asdfer' 中的每一个元素
  9. react hooks使用_如何开始使用React Hooks:受控表格
  10. JQuery 加载 CSS、JS 文件
  11. linux 内核空间 缺页,Linux-3.14.12内存管理笔记【缺页异常处理(1)】
  12. 数据科学家:我的工作就是发现别人未知的
  13. Angular 7和 .NET Core 2.2——全球天气(第2部分)
  14. 5款免费又好用的甘特图软件,总有一款适合你
  15. 《暗时间》经典(二)
  16. 将图片放大如何保持图片的清晰度?
  17. 彩印包装印刷行业erp-轻松、易用
  18. Powerdesigner显示表的comment和列的comment的方法
  19. Linux机械硬盘初始化,教你如何初始化外接盒中的硬盘
  20. 看黑客如何在Black Hat 2016上5秒干掉 macOS 系统,“催吐”ATM机| 宅客周刊

热门文章

  1. 思科ACL不连续通配符掩码的计算
  2. 开源解决方案_OpenProject:一个开源项目管理解决方案
  3. phpize mysql_phpize增加php模块
  4. saltstack配置管理数据系统
  5. mysql企业实战_实战MySQL服务器企业技术 实战进阶学习篇 企业级MySQL实战进阶视频教程...
  6. 【WINDOWS / DOS 批处理】findstr命令之参数详解(一)
  7. 著名大型汽车冲压模具厂商Fuji Technica使用NCspeed为特斯拉提供最优质产品
  8. JVM常见的垃圾回收器
  9. inline-block和block的区别
  10. PG 备份策略及 WAL 日志清理策略