概要
Launcher3项目地址:AOSP源码/packages/apps/Launcher3
Launcher3自定义桌面应用,我目前实践有两种方式:
- 更改默认的布局文件,指定主屏幕添加哪些应用
- 代码中动态添加app到主屏幕中(包括删除原先的应用icon、新增)
更改默认布局
提示:要根据屏幕大小自己去找哪个布局文件
1、进入launcher3布局的源码路径(packages/apps/Launcher3/res/xml)找到要修改的default_workspace_axb.xml
重点关注下:devices_profiles.xml ,在这个文件里面指定加载那些default_workspace_axb.xml
更简单的方法:aosp编译后,运行模拟器,在launcher桌面下,长按图标拖动,一个格子一个格子的数,就可以知道当前项目中用的是几行几列的布局了
比如我的设备应用的是default_workspace_5x5.xml,打开这个文件,显示如下:
标签就是指定应用的,其中的launcher:container="-101"代表加入到hotseat中的应用,launcher:x=“0” 指定第几列,launcher:y="0"指定第几行,因此在这里就可以更改hotseat中应用及其位置关系。
往下看:
这里没有launcher:container=“-101” 的就代表workspace(主屏幕)中的应用,因此在这里更改launcher:uri的内容即可更换应用。同时修改launcher:screen="0"代表在哪个屏幕,x,y代表在哪个位置(-1是默认值:第一行或者第一列)
综上所述:更改布局文件后,重新编译aosp即可看到launcher屏幕中的应用已经被修改了。
如果你修改了布局文件,但是重新编译后运行模拟器,发现桌面应用并没有改变,有可能是launcher的database没有更新,因为这些布局文件的内容,在launcher第一次开机启动时会创建database并保存数据到其中,后续有使用直接从db读取,而不用重复读布局文件
adb root
adb shell rm /data/data/com.android.launcher3/databases/launcher.db
再重启模拟器即可生效
数据库中记录的主屏幕应用信息如下:
代码中动态添加app到主屏幕
有这种功能:用户在All apps界面(也就是那个上拉抽屉界面)选择几个应用,需要添加到主屏幕,这种只能通过代码的形式来动态添加了
修改地址:/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
假设已经有了需要添加的应用列表List<AppInfo>
和对应的响应事件changeWorkspaceItems
第一步:
删除原先workspace中的应用,Launcher.java中已经提供了相关的方法removeItem()
/**
* Launcher中默认已经提供了删除应用的方法
* @param v 要移除的应用的view 应用图标以BubbleTextView的形式显示的,具体可以去看这个类咋操作的
* @param itemInfo 要移除的应用信息,根据这个信息去db中删除对应的元素
* @param deleteFromDb 是否要删除数据库中的数据
*/
public boolean removeItem(View v, final ItemInfo itemInfo, boolean deleteFromDb) {
return removeItem(v, itemInfo, deleteFromDb, null);
}
(1)我们只需要构建一个哈希表去存储主屏幕应用信息以及其对应的view即可。
在Launcher.java中新建HashMap并在onCreate()中创建该对象
private Map<ItemInfo, View> homeIconMap;
在Launcher#bindItems()
方法中收集主屏幕应用信息到哈希表中
在有了哈希表后,就可以在后续需要删除的时候使用这个方法。
(2)在Launcher.java中新建删除方法removeWorkspaceItems
public void removeWorkspaceItems(HashMap<ItemInfo, View> orignItemsMap){
Set<ItemInfo> itemInfos = orignItemsMap.keySet();
for (ItemInfo info: itemInfos){
View icon = orignItemsMap.get(info);
// 调用launcher中原生的方法删除应用,底层就是调的contentProvider来删除对应的数据表信息
removeItem(icon, info, true);
}
}
第二步:在Launcher.java中新建新增方法addToWorkspace
public void addToWorkspace(List<AppInfo> appInfoList){
// AppInfo就是all apps界面中的每个应用的对应的数据结构
// 具体可以看:
// 1、LoaderTask#loadAllApps() 这些all apps数据怎么来的
// 2、Launcher#bindAllApplications() 怎么添加到all apps界面的
// 获取用户信息,默认就一个
UserManager mUserManager = getSystemService(UserManager.class);
final List<UserHandle> profiles = mUserManager.getUserProfiles();
// 遍历添加集合,添加到主屏幕中
for(AppInfo appInfo: appInfoList){
// 得到包名
String packageName = appInfo.componentName.getPackageName();
ItemInstallQueue.INSTANCE.get(mContext)
.queueItem(packageName, profiles.get(0));
}
}
第三步:组装上面第一步和第二步的方法到添加事件中:changeWorkspaceItems
public void changeWorkspaceItems(){
// 1 删除原先应用 homeIconMap在Launcher启动时我们已经收集好信息
removeWorkspaceItems(homeIconMap);
// 2 添加新的应用
// 一般可以通过这个去获取: AppInfo[] allInfo = mModel.mBgAllAppsList.copyData();
List<AppInfo> listView = "我们事先准备好的集合"
addToWorkspace(listView);
}
至于changeWorkspaceItems
这个方法的调用就取决于个人了,比如写个button的点击事件去响应等等。
经过我的踩坑,changeWorkspaceItems
不要写在子线程中,因为:删除、新增方法最终会在相关的handler去执行,本身就是异步的,所以不要多此一举去开子线程执行了,否则可能会报错。
小结
添加应用到主屏幕中,我所尝试的这两种方式均可以。
方法二:用代码动态添加app到主屏幕,只是我自己阅读源码找到的方案,可能还有其他方案也能实现,这里只是提供一个参考吧。
大家有什么疑问或者建议欢迎向我留言,本人技术有限,如果有误也请不吝赐教~~。