Android.Settings类&设置默认输入法
Posted wkw1125
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android.Settings类&设置默认输入法相关的知识,希望对你有一定的参考价值。
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)
//获取系统已安装的输入法ID
String[] 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类&设置默认输入法的主要内容,如果未能解决你的问题,请参考以下文章
Android Settings 取消全选效果改为直接选中选项
Android Settings 修复多用户 修复添加访客界面卡住
Android 11.0 修复Settings→添加访客时界面卡住
从 QT 应用程序(com.android.settings)打开 android 设置