安卓13的Launcher3作为系统级应用,其源码结构相比前代有了显著变化。我接手OEM项目时,发现新版本将核心布局逻辑集中在了几个关键类中。先带大家看看整体架构:
res/xml/目录下的device_profiles.xml是布局的总控制台,这里定义了手机/平板等不同设备的网格参数Workspace.java负责管理桌面页面的生命周期,CellLayout处理具体图标排列DeviceProfile.java根据当前设备特性动态计算布局参数实际修改中遇到的一个典型坑是:当在device_profiles.xml里修改了网格参数后,发现桌面图标仍然错位。后来通过断点调试发现,DeviceProfile.calculateCellSize()方法会覆盖配置文件中的部分参数。解决方案是在InvariantDeviceProfile.initialize()方法里强制指定minWidthPx和minHeightPx的值。
搜索框的显示控制涉及三个层面的修改:
在device_profiles.xml中找到对应设备的grid-option节点(例如6x5布局),关键参数包括:
xml复制launcher:numSearchContainerColumns="5" <!-- 搜索框横向占位格数 -->
launcher:borderSpaceHorizontal="16" <!-- 水平边距 -->
实测发现,修改numSearchContainerColumns后需要同时调整borderSpaceHorizontal,否则会出现搜索框被截断的情况。建议值:
Workspace.java中的bindAndInitFirstWorkspaceScreen()方法控制搜索框的初始位置。修改时注意:
java复制CellLayoutLayoutParams lp = new CellLayoutLayoutParams(
1, // 纵向起始格(从0计数)
2, // 横向起始格
cellHSpan,
1 // 纵向占位格数
);
这里有个隐藏坑:当设备旋转时,FeatureFlags.QSB_ON_FIRST_SCREEN标志位可能导致搜索框消失。需要在onConfigurationChanged()里手动调用rebindWorkspace()。
对于某些定制ROM,可能需要通过微件方式添加搜索框。在default_workspace_6x5.xml中添加:
xml复制<appwidget
container="-100"
screen="0"
x="1" y="2"
spanX="5" spanY="1"
packageName="com.google.android.googlequicksearchbox"
className="com.google.android.googlequicksearchbox.SearchWidgetProvider"/>
注意container="-100"表示主屏幕,-101是Hotseat区域。遇到过华为EMUI系统会忽略这个配置,需要在Partner.java中重写getDefaultLayout()方法。
在device_profiles.xml中修改网格密度:
xml复制<grid-option
launcher:name="6_by_5"
launcher:numRows="6"
launcher:numColumns="7"
launcher:allAppsColumns="6">
这里有个性能陷阱:numRows超过6会导致AllAppsContainerView加载时卡顿。解决方案是在AppsRecyclerView.setAdapter()里启用setItemViewCacheSize(20)。
通过partner_default_layout.xml控制预装应用位置:
xml复制<favorite
screen="0"
x="5" y="3"
packageName="com.android.vending"
className="com.android.vending.AssetBrowserActivity"/>
遇到过小米设备不识别这个配置的问题,需要在LauncherProvider.java的loadDefaultFavoritesIfNecessary()方法里强制加载。
要实现按使用频率动态排序,需要修改ItemInfo.java:
java复制public void updateRank(Launcher launcher) {
this.rank = launcher.getStatsLogManager()
.getUsageStats(this.user)
.getAppLaunchCount(this.componentName);
}
然后在WorkspaceItemInfo.java的onBind()里调用。注意要在AndroidManifest.xml中添加USAGE_STATS_SERVICE权限。
在device_profiles.xml中:
xml复制launcher:numHotseatIcons="0" <!-- 0隐藏Hotseat -->
launcher:isTaskbarPresent="true" <!-- 启用任务栏模式 -->
修改后会出现ArithmeticException异常,需要在DeviceProfile.java中修复:
java复制int hotseatCellSize = numShownHotseatIcons > 0 ?
(hotseatBarSize - 2 * hotseatBarSidePadding) / numShownHotseatIcons :
hotseatBarSize;
通过taskbar_offset.xml调整位置:
xml复制<dimen name="taskbar_button_margin_6_5">24dp</dimen>
实测发现还需要修改TaskbarViewController.java中的getTaskbarWindowMargin()方法:
java复制int margin = isGesturalMode ?
resources.getDimensionPixelSize(R.dimen.taskbar_button_margin_6_5) : 0;
针对折叠屏设备,需要在DeviceProfile.kt中添加:
kotlin复制fun isTablet(): Boolean {
return minWidthDp >= 600 && !isTwoPanels
}
然后在LauncherAppState.java的onConfigurationChanged()里监听屏幕变化。
使用ADB命令快速验证修改:
bash复制adb shell am broadcast -a com.android.launcher3.action.FORCE_RELOAD
配合LayoutInspector查看视图层级时,需要先在Launcher.java里设置DEBUG_DRAW=true。
在LauncherModel.java中添加:
java复制private void trimMemory() {
mIconCache.clear();
mWidgetsModel.clear();
}
并重写onTrimMemory()回调。实测可减少20%内存占用。
在Android.bp中添加:
python复制ccache {
enabled: true,
size: "10G"
}
同时使用mka Launcher3 -j16并行编译。我的i9处理器编译时间从8分钟降到2分钟。