本文主要分析launcher3 如何加载默认的icon ,基于AOSP Q Launcher3 code
1、 launcher首先会初始化设备配置属性,比如加载哪些图标,图标布局n * n等等,这些配置定义在device_profiles.xml 中,device_profiles.xml 会关联到default_workspace_n*n.xml,
2、 在LoaderTask.java 的loadworkspace函数中会去load默认的布局,其实就是去加载 1中初始化后的配置
1、InvariantDeviceProfile初始化
Launcher在oncreate的时候会通过单例初始化LauncherAppState类
LauncherAppState app = LauncherAppState.getInstance(this);
在LauncherAppState的构造中会初始化InvariantDeviceProfile,先看一下InvariantDeviceProfile构造函数,
public InvariantDeviceProfile(Context context) {
......
// This guarantees that width < height
minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm);
minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm);
ArrayList<InvariantDeviceProfile> closestProfiles = findClosestDeviceProfiles(
minWidthDps, minHeightDps, getPredefinedDeviceProfiles(context));
InvariantDeviceProfile interpolatedDeviceProfileOut =
invDistWeightedInterpolate(minWidthDps, minHeightDps, closestProfiles);
InvariantDeviceProfile closestProfile = closestProfiles.get(0);
numRows = closestProfile.numRows;
numColumns = closestProfile.numColumns;
numHotseatIcons = closestProfile.numHotseatIcons;
//这个布局就是后面load default favorites加载所需要的布局id
defaultLayoutId = closestProfile.defaultLayoutId;
Log.d("InvariantDeviceProfile", "InvariantDeviceProfile: defaultLayoutId: " + defaultLayoutId);
demoModeLayoutId = closestProfile.demoModeLayoutId;
numFolderRows = closestProfile.numFolderRows;
numFolderColumns = closestProfile.numFolderColumns;
......
通过getPredefinedDeviceProfiles 去load device_profiles.xml中定义的所有profile,放到List中,然后通过findClosestDeviceProfiles从 list中找出最接近的profile。
/**
* Returns the closest device profiles ordered by closeness to the specified width and height
*/
// Package private visibility for testing.
ArrayList<InvariantDeviceProfile> findClosestDeviceProfiles(
final float width, final float height, ArrayList<InvariantDeviceProfile> points) {
// Sort the profiles by their closeness to the dimensions
ArrayList<InvariantDeviceProfile> pointsByNearness = points;
Collections.sort(pointsByNearness, new Comparator<InvariantDeviceProfile>() {
public int compare(InvariantDeviceProfile a, InvariantDeviceProfile b) {
return Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),
dist(width, height, b.minWidthDps, b.minHeightDps));
}
});
return pointsByNearness;
}
2、LoadWorkspace 加载默认的favorites
loadworkspace()是加载添加在workspace上的 shortcut、folder、widget,这里我们只看如何加载默认的图标。
Log.d(TAG, "loadWorkspace: loading default favorites");
LauncherSettings.Settings.call(contentResolver,
LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
通过ContentResolver的call方法调用到LauncherProvider去实现,看一下launcherprovider call实现,
@Override
public Bundle call(String method, final String arg, final Bundle extras) {
createDbIfNotExists();
switch (method) {
......
case LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES: {
loadDefaultFavoritesIfNecessary();
return null;
}
......
loadDefaultFavoritesIfNecessary()这个流程就是找到之前已经初始化好的device profile,通过InvariantDeviceProfile中的defaultLayoutId找到对应的default_workspace_n*n.xml,然后解析加载是数据并插入到数据库中,可以看一下测试打印的调用栈
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.LauncherProvider$DatabaseHelper.insertAndCheck(LauncherProvider.java:1020)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.AutoInstallsLayout.addShortcut(AutoInstallsLayout.java:304)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.DefaultLayoutParser$AppShortcutWithUriParser.invalidPackageOrClass(DefaultLayoutParser.java:136)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.AutoInstallsLayout$AppShortcutParser.parseAndAdd(AutoInstallsLayout.java:374)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.DefaultLayoutParser$AppShortcutWithUriParser.parseAndAdd(DefaultLayoutParser.java:91)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.DefaultLayoutParser$ResolveParser.parseAndAdd(DefaultLayoutParser.java:220)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.AutoInstallsLayout.parseAndAddNode(AutoInstallsLayout.java:284)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.AutoInstallsLayout.parseLayout(AutoInstallsLayout.java:225)
10-28 16:40:46.334 D/LauncherProvider(32452): com.android.launcher3.AutoInstallsLayout.loadLayout(AutoInstallsLayout.java:201)
10-28 16:40:46.335 D/LauncherProvider(32452): com.android.launcher3.LauncherProvider$DatabaseHelper.loadFavorites(LauncherProvider.java:1060)
10-28 16:40:46.335 D/LauncherProvider(32452): com.android.launcher3.LauncherProvider.loadDefaultFavoritesIfNecessary(LauncherProvider.java:492)
10-28 16:40:46.335 D/LauncherProvider(32452): com.android.launcher3.LauncherProvider.call(LauncherProvider.java:392)
10-28 16:40:46.335 D/LauncherProvider(32452): android.content.ContentProvider$Transport.call(ContentProvider.java:401)
10-28 16:40:46.335 D/LauncherProvider(32452): android.content.ContentResolver.call(ContentResolver.java:1756)
10-28 16:40:46.335 D/LauncherProvider(32452): com.android.launcher3.LauncherSettings$Settings.call(LauncherSettings.java:312)
10-28 16:40:46.335 D/LauncherProvider(32452): com.android.launcher3.model.LoaderTask.loadWorkspace(LoaderTask.java:263)
10-28 16:40:46.335 D/LauncherProvider(32452): com.android.launcher3.model.LoaderTask.run(LoaderTask.java:168)
另外,loadDefaultFavoritesIfNecessary() 通过判断if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) 是否要加载默认的workspace,一般情况下,只会加载一次,除非删除launcher.db数据库,EMPTY_DATABASE_CREATED这个key在db创建的时候会设为true,一旦加载default workspace完成,则会remove EMPTY_DATABASE_CREATED key。