在android 盒子定制开发中,时常会遇到需要修改高级设置Settings内容的需求,比如在海思3798MV200方案中,“显示”菜单和“高级设置”菜单都是调整HDMI视频显示相关的设置,但“显示”菜单在“设备”分类下,“高级设置”菜单在“系统”分类下,且相隔较远,操作起来不太方便。现在想把“高级设置”菜单移动到“设备”分类下,并且位于“显示”菜单之后,该如何处理呢?
步骤一:在AndroidManifest.xml中修改菜单所属分类
找到“高级设置”对应的Activity注册位置:AdvanceOptionsActivity,修改meta-data标签中category属性分类名称。如下:
原先定义为“system"系统分类
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.system" />
修改为“device"设备分类,并将优先级priority属性值调整为跟“显示”菜单一样
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.device" />
<intent-filter android:priority="9">
<action android:name="com.android.settings.action.SETTINGS" />
</intent-filter>
如图:
步骤二:在SettingsActivity中修改显示顺序:
在activity数组SETTINGS_FOR_RESTRICTED[]中和对应的fragment数组ENTRY_FRAGMENTS[]中修改对应顺序:将AdvanceOptionsActivity放到DisplaySettingsSTBActivity之后,将fragment 中,AdvanceOptions放到DisplaySettingsSTB之后
除了修改一级菜单位置和名称等,有时还需要定制跳转的第三方应用,比如恢复出厂和系统升级菜单,想跳转到客户提供的apk,可在SettingsActivity中,switchToFragment方法中通过拦截原生跳转,重定位到定制apk中。例如:
/**
* Switch to a specific Fragment with taking care of validation, Title and BackStack
*/
private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
boolean addToBackStack, int titleResId, CharSequence title, boolean withTransition) {
Log.i("Settings","===switchToFragment=="+fragmentName+"==title="+title);
if(fragmentName.equals("com.android.settings.UpgradeSettings")){ //原生系统升级
PackageManager packageManager = getPackageManager();
Intent intent1 = packageManager.getLaunchIntentForPackage("com.eweat.systemupdate"); //第三方
if(intent1 != null) {
startActivity(intent1);
}
return null;
}else if(fragmentName.equals("com.android.settings.PrivacySettings")){ //原生恢复出厂
PackageManager packageManager = getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage("com.test.reset"); //第三方
if(intent != null) {
startActivity(intent);
}
return null;
}
if (validate && !isValidFragment(fragmentName)) {
throw new IllegalArgumentException("Invalid fragment for this activity: "
+ fragmentName);
}
Fragment f = Fragment.instantiate(this, fragmentName, args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(mMainContentId, f);
if (withTransition) {
TransitionManager.beginDelayedTransition(mContent);
}
if (addToBackStack) {
transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
}
if (titleResId > 0) {
transaction.setBreadCrumbTitle(titleResId);
} else if (title != null) {
transaction.setBreadCrumbTitle(title);
}
transaction.commitAllowingStateLoss();
getFragmentManager().executePendingTransactions();
return f;
}
不过这样拦截跳转有个漏洞就是按返回键的时候会跳转到系统被拦截原生界面,而不是直接返回一级菜单界面,因为拦截过程相当于在系统二级fragment界面刚显示时强行进行跳转到第三方应用。
所有需要在onResume中也进行拦截处理,让它返回上一级时直接返回到一级菜单。我的处理方式是模拟发送一次返回键值,整个结果,相当于连续按了两次返回键。所以这个方法虽然能达到效果,但并不是一个好的实现方式。如下:
@Override
protected void onResume() {
super.onResume();
if( null != getWindow() && null != getWindow().getDecorView())
{
if(this.toString().contains("com.android.settings.Settings@"))
{
return;
}
if(this.toString().contains("com.android.settings.Settings$UpgradeSettingsActivity")
|| this.toString().contains("com.android.settings.Settings$PrivacySettingsActivity")){ //系统升级
new Thread() {
public void run() {
try {
SystemClock.sleep(100);
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(4);
SystemClock.sleep(100);
// Log.i("song","send keycode finish=======");
} catch (Exception e) {
e.printStackTrace();
// Log.i("song","send keycode error======="+e.toString());
}
}
}.start();
return;
}
....
以上