Android Framework-Launcher-InvariantDeviceProfile
在上一篇我们对device_profiles.xml
进行了解析,获取了其中的属性,本篇主要看一下默认布局的加载。
launcher:defaultLayoutId="@xml/default_workspace_5x5"
默认桌面布局的XML
资源路径,定义了首次使用该方案时,系统预装应用(如电话、短信)的默认位置。
这里我们先跳过基础流程直接进入到 LoaderTask
LoaderTask
继承 Runnable
,直接进入对应的run
方法。
java
//packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
public void run()
//省略...
try {
loadWorkspace(allShortcuts, memoryLogger);
} finally {
Trace.endSection();
}
//省略...
}
// 调用到-->
LauncherSettings.Settings.call(contentResolver,
LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
//-->
LauncherProvider 中的call 方法中的
case LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES: {
loadDefaultFavoritesIfNecessary();
return null;
}
loadDefaultFavoritesIfNecessary
负责多种布局的加载,其中包括 auto
,partner
,和默认布局。 默认情况下走默认布局,国内基本没有auto
, partner
是一种默认占位方法。
java
synchronized private void loadDefaultFavoritesIfNecessary() {
SharedPreferences sp = LauncherPrefs.getPrefs(getContext());
if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) {
Log.d(TAG, "loading default workspace");
LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder();
AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHolder);
if (loader == null) {
loader = AutoInstallsLayout.get(getContext(), widgetHolder, mOpenHelper);
}
if (loader == null) {
final Partner partner = Partner.get(getContext().getPackageManager());
if (partner != null) {
int workspaceResId = partner.getXmlResId(RES_PARTNER_DEFAULT_LAYOUT);
if (workspaceResId != 0) {
loader = new DefaultLayoutParser(getContext(), widgetHolder,
mOpenHelper, partner.getResources(), workspaceResId);
}
}
}
final boolean usingExternallyProvidedLayout = loader != null;
if (loader == null) {
loader = getDefaultLayoutParser(widgetHolder);
}
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
// Populate favorites table with initial favorites
if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
&& usingExternallyProvidedLayout) {
// Unable to load external layout. Cleanup and load the internal layout.
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
getDefaultLayoutParser(widgetHolder));
}
clearFlagEmptyDbCreated();
widgetHolder.destroy();
}
}
getDefaultLayoutParser()
,idp.demoModeLayoutId
这一句,我们在之前InvariantDeviceProfile
可以知道,defaultLayoutId
其实就是之前布局里获取到的default_workspace_5x5.xml
。最终构建一个可以解析xml
文件属性的 Parser
返回。
java
private DefaultLayoutParser getDefaultLayoutParser(LauncherWidgetHolder widgetHolder) {
InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
int defaultLayout = mDefaultWorkspaceLayoutOverride > 0
? mDefaultWorkspaceLayoutOverride : idp.defaultLayoutId;
if (getContext().getSystemService(UserManager.class).isDemoUser()
&& idp.demoModeLayoutId != 0) {
defaultLayout = idp.demoModeLayoutId;
}
return new DefaultLayoutParser(getContext(), widgetHolder,
mOpenHelper, getContext().getResources(), defaultLayout);
}
我们看一下该xml
文件,该文件决定了首页布局。
xml
<?xml version="1.0" encoding="utf-8"?>
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
<!-- Dialer, Messaging, [Maps/Music], Browser, Camera -->
<resolve
launcher:container="-101"
launcher:screen="0"
launcher:x="0"
launcher:y="0" >
<favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" />
<favorite launcher:uri="tel:123" />
<favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" />
</resolve>
<resolve
launcher:container="-101"
launcher:screen="1"
launcher:x="1"
launcher:y="0" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" />
<favorite launcher:uri="sms:" />
<favorite launcher:uri="smsto:" />
<favorite launcher:uri="mms:" />
<favorite launcher:uri="mmsto:" />
</resolve>
<resolve
launcher:container="-101"
launcher:screen="2"
launcher:x="2"
launcher:y="0" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;end" />
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MUSIC;end" />
</resolve>
<resolve
launcher:container="-101"
launcher:screen="3"
launcher:x="3"
launcher:y="0" >
<favorite
launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
<favorite launcher:uri="http://www.example.com/" />
</resolve>
<resolve
launcher:container="-101"
launcher:screen="4"
launcher:x="4"
launcher:y="0" >
<favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
<favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
</resolve>
<!-- Bottom row -->
<resolve
launcher:screen="0"
launcher:x="0"
launcher:y="-1" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
<favorite launcher:uri="mailto:" />
</resolve>
<resolve
launcher:screen="0"
launcher:x="1"
launcher:y="-1" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
<favorite launcher:uri="#Intent;type=images/*;end" />
</resolve>
<resolve
launcher:screen="0"
launcher:x="4"
launcher:y="-1" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MARKET;end" />
<favorite launcher:uri="market://details?id=com.android.launcher" />
</resolve>
</favorites>
基础属性
-
className
一般就是主页名称可以通过adb命令拿到 -
packageName
应用包名 -
launcher:x
和launcher:y
在屏幕的坐标位置 ,比如 5X5,就是横竖5个格子,x代表横坐标,y代表纵坐标。
-
screen
屏幕 0 是主屏幕 ,在
hotset
上是顺序排列从0开始。 -
spanX
和spanY
占据的格子数量 可以理解为5*5就是横着5个格子 竖着5个格子
-
appwidget
桌面小组件
-
favorite
应用,底部快捷(
hotset
)也使用favorite
,只是需要container
需要写-101
。 -
folder
文件夹
title
就是文件夹名称文件夹里的的应用为
favorite
, 需要两个上才可以构建文件夹。
在构建loader
成功以后, mOpenHelper.loadFavorites()
我们简单理解为入库就行,到此位置,数据库里已经有了默认布局的数据。