Settings.apk 6.0开发记录

其apk在设备上的位置:/system/priv-app/Settings。

开发前准备

  • 除了需要导入Settings的源码,还需导入SettingsLib模块作为依赖
  • 在app目录下新建systemlib目录作为系统库,需添加 如下jar包作为Provider,具体参考模块依赖
    • android_stubs_current_intermediates.jar
    • bouncycastle_intermediates.jar
    • conscrypt_intermediates.jar
    • core-libart_intermediates.jar
    • ext_intermediates.jar
    • framework_intermediates.jar
    • frameworks-core-util-lib_intermediates.jar
    • ims-common_intermediates.jar
    • jsr305_intermediates.jar
    • setup-wizard-lib_intermediates.jar
    • setup-wizard-navbar_intermediates.jar
    • telephony-common_intermediates.jar
  • 整理资源文件,补齐缺失的资源 直到编译通过

一级选项添加流程 以有线网络为例

1.Settings中一级选项的显示是在dashboard_categories.xml中添加的,路径为main\res\xml\,Favorites中有收藏此文件。打开dashboard_categories.xml,选项是按组分类的,如无线和网络、设备、系统,我们自定义的无线网络放在无线和网络组中。先创建EthernetFragment,通过title(Wireless&network)找到无线和网络的dashboard-category。
在上述组里添加如下代码

<dashboard-tile
 //此id要添加到SettingsActivity的SETTINGS_FOR_RESTRICTED数组中,如果id不存在此数组,加载时会移除
android:id="@+id/ethernet_settings"
android:title="有线网络" 
//此Fragment为之前创建的路径,名称要添加到SettingsActivity的ENTRY_FRAGMENTS数组中
android:fragment="com.android.settings.shine.EthernetFragment"
android:icon="@drawable/ic_settings_data_usage"/>

2.在Settings.java中添加如下代码

 public static class EthernetSettingsActivity extends SettingsActivity {  }

3.在manifest中注册EthernetSettingsActivity

 <activity
    android:name=".Settings$EthernetSettingsActivity"
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:label="有线网络设置"
    android:taskAffinity="">
        <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <action android:name="android.settings.ETHERNET_SETTINGS"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.VOICE_LAUNCH"/>
        <category android:name="com.android.settings.SHORTCUT"/>
        </intent-filter>
    //当点击添加的有线网络选项时会跳转到此页面
        <meta-data
            android:name="com.android.settings.FRAGMENT_CLASS"
            //真正显示的内容,路径与dashboard_categories.xml中注册的一样
            android:value="com.android.settings.shine.EthernetFragment"/>
        <meta-data
    android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
    //id与dashboard_categories.xml中注册的一样
    android:resource="@id/ethernet_settings"/>
    </activity>

4.添加有线网络选项的id到SettingsActivity的SETTINGS_FOR_RESTRICTED数组中

private int[] SETTINGS_FOR_RESTRICTED = {
    R.id.wireless_section,//无线
    R.id.wifi_settings,//wifi
    R.id.bluetooth_settings,//蓝牙
    R.id.data_usage_settings,
    R.id.ethernet_settings,//有线网络
    R.id.server_settings,....}

5.将EthernetFragment类名添加到SettingsActivity的ENTRY_FRAGMENTS数组

private static final String[] ENTRY_FRAGMENTS = {
    WirelessSettings.class.getName(),
    EthernetFragment.class.getName(),//有线网络
    ServerSettingFragment.class.getName(),//服务器设置
    OnOffSettingFragment.class.getName(),//开关机设置
    ...}

添加退出选项

退出不需要进入子页面,则不需要注册Activity和添加Fragment。同样打开dashboardcategories.xml,我们把退出选项添加在系统组里,知道title为System的dashboard-category,添加如下代码

 <dashboard-tile
    //此id可作为身份判断
    android:id="@+id/exit_settings"
    android:title="退出"
    android:icon="@drawable/ic_settings_about"
    />

直接在DashboardTileView的OnClick方法中添加退出点击处理

public void onClick(View v) {
    if (mTile.fragment != null) {
        Utils.startWithFragment(getContext(), mTile.fragment, mTile.fragmentArguments, null, 0,
                mTile.titleRes, mTile.getTitle(getResources()));
    } else if (mTile.intent != null) {
        int numUserHandles = mTile.userHandle.size();
        if (numUserHandles > 1) {
            ProfileSelectDialog.show(((Activity) getContext()).getFragmentManager(), mTile);
        } else if (numUserHandles == 1) {
            getContext().startActivityAsUser(mTile.intent, mTile.userHandle.get(0));
        } else {
            getContext().startActivity(mTile.intent);
        }
    }else if (mTile.id == R.id.exit_settings) {
        //点击退出按钮退出应用
        ((SettingsActivity)getContext()).finish();
    }
}

移除选项,比如位置选项

在SettingsActivity中的updateTilesList()方法里添加如下代码

private void updateTilesList(List<DashboardCategory> target) {
    ....省略一批代码
 // Ids are integers, so downcasting is ok
    int id = (int) category.id;
    int n = category.getTilesCount() - 1;
    while (n >= 0) {
    ....省略一批代码
        else if (id == R.id.location_settings) {
         removeTile=true;
       }
    ....省略一批代码
    n--;
    }

6.0系统默认永不休眠,要显示这个选项,打开app\src\main\res\values\custom_config.xml文件,修改代码如下

 <bool name="config_show_screen_off_never_timeout" translatable="false">true</bool>

系统默认的高亮色比较淡,不容易区分条目是否被选中,打开\src\main\res\values\themes.xml文件,在如下样式中添加自定义背景色

<style name="Theme.Settings" parent="Theme.SettingsBase">
...省略其他样式设置
//修改高亮色
<item name="android:colorControlHighlight">@color/memory_user_light</item>
</style>

屏幕旋转的处理,显示选项和后台都能控制设备的旋转,前提是Launcher允许桌面旋转(具体操作查看Launcher.apk的修改记录),否则只会应用旋转,桌面不会同步旋转;代码如下,需在子线程中执行:

IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
//保存到全局
Settings.System.putInt(getContentResolver(),Settings.System.USER_ROTATION, value);
//保存到数据库,与后台同步
ShineDataBaseHelper.getInstance(this).save(Common.DESKTOP_ORIENTATION, data);
try {
    wm.freezeRotation(value);
    WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
    wallpaperManager.setBitmap(wallpaperManager.getBitmap());
    Log.d(TAG, "设置旋转完成");
} catch (RemoteException | IOException e) {
    Log.d(TAG, "设置旋转异常");
    e.printStackTrace();
}

提示音和通知选项,在src\main\java\com\android\settings\notification\NotificationSettings.java文件中移除了闹钟和铃音设置,只留下媒体音量,其功能实现在src\main\java\com\android\settings\notification\VolumeSeekBarPreference.java文件中。
主要改动有修改了SeekBarPreference的源码,否则SeekBar控件找不到报空,打开src\main\res\layout\preference_volume_slider.xml,修改id

<SeekBar 
    //@*android:id/seekbar 源代码
    android:id="@+id/seekbar"
    android:layout_marginStart="24dp"
    android:layout_gravity="center_vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

拷贝SeekBarPreference源码到项目,使VolumeSeekBarPreference继承之,本项目路径为E:\workspace_a64\Settings\app\src\main\java\com\android\settings\shine\SeekBarPreference.java。修改SeekBarPreference的onBindView方法:

@Override
protected void onBindView(View view) {
    super.onBindView(view);
    SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
//  SeekBar seekBar = (SeekBar) view.findViewById( com.android.internal.R.id.seekbar);
    ...
}

打开VolumeSeekBarPreference.java文件,添加遥控器调节音量的响应,具体修改参考源文件

@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
    if (event.getAction() != KeyEvent.ACTION_UP) {
        if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
                || keyCode == KeyEvent.KEYCODE_EQUALS) {
            mSeekBar.setProgress(mSeekBar.getProgress() + 1);
            mVolumizer.onProgressChanged(mSeekBar,mSeekBar.getProgress(),true);
            return true;
        }
        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
            mSeekBar.setProgress(mSeekBar.getProgress() - 1);
            mVolumizer.onProgressChanged(mSeekBar,mSeekBar.getProgress(),true);
            return true;
        }
    }
    return false;
}

显示输入法,在系统完成Boot,调用以下方法,在SettingProvider中没有找到默认设置

Settings.Secure.putInt(getContentResolver(), "show_ime_with_hard_keyboard", 1);

修改PhoneWindowManager.java源码,设定对F12按键响应,使遥控器对设置应用的直接调用。找到interceptKeyBeforeDispatching方法添加如下代码:

@Override
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
...
...
 if (keyCode == KeyEvent.KEYCODE_HOME) {
...响应首页键
...其他按键
}else if(keyCode == KeyEvent.KEYCODE_F12){
    if(down){
        //应用的首页需在清单文件添加类别android.intent.category.SETTINGS
        Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, "android.intent.category.SETTINGS");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
        } catch (ActivityNotFoundException ex) {
           ...
        }
    }
        return -1;   
    }
....
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容