一、启动流程

AMS startHomeOnAllDisplays。
//查询符合条件的home
/frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
int flags, int userId,
boolean resolveForStart,
int filterCallingUid) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final ResolveInfo bestChoice =
chooseBestActivity(intent, resolvedType, flags, query, userId);
return bestChoice;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
二、编译
以展锐 Android10平台为例。编译时用 make Launcher3QuickStep -j4 ,而不是 make Launcher3 -j4
三、源码分析
Launcher.java是Launcher的启动页面,负责资源初始化和桌面UI创建。对应布局 launcher.xml。
3.1Launcher.java
protected
super.onCreate(savedInstanceState);
// 获取 LauncherAppState 实例和模型
LauncherAppState app = LauncherAppState.getInstance(this);
mModel = app.getModel();
// 初始化不变的设备配置文件
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
initDeviceProfile(idp);
idp.addOnChangeListener(this);
// 获取共享首选项和图标缓存
mSharedPrefs = LauncherPrefs.getPrefs(this);
mIconCache = app.getIconCache();
// 创建无障碍代理
mAccessibilityDelegate = createAccessibilityDelegate();
// 初始化拖动控制器
initDragController();
// 创建所有应用程序控制器
mAllAppsController = new AllAppsTransitionController(this);
// 创建状态管理器
mStateManager = new StateManager<>(this, NORMAL);
// 创建引导首选项
mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
// 设置视图
setupViews();
// 初始化Widget
mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHolder = createAppWidgetHolder();
mAppWidgetHolder.startListening();
// 设置内容视图
setContentView(getRootView());
ComposeInitializer.initCompose(this);
}
3.1.1setupViews方法
protected
// 创建根视图
inflateRootView(R.layout.launcher);
// 获取拖动层和焦点处理器
mDragLayer = findViewById(R.id.drag_layer);
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
// 获取工作区、总览面板和Hotseat
mWorkspace = mDragLayer.findViewById(R.id.workspace);
mWorkspace.initParentViews(mDragLayer);
mOverviewPanel = findViewById(R.id.overview_panel);
mHotseat = findViewById(R.id.hotseat);
// 将工作区设置为Hotseat
mHotseat.setWorkspace(mWorkspace);
// 设置拖动层
mDragLayer.setup(mDragController, mWorkspace);
// 设置工作区
mWorkspace.setup(mDragController);
// 在工作区绑定之前,确保我们将壁纸偏移锁定到默认状态,否则在RTL中我们将更新错误的偏移量
mWorkspace.lockWallpaperToDefaultPage();
mWorkspace.bindAndInitFirstWorkspaceScreen();
mDragController.addDragListener(mWorkspace);
// 获取搜索/删除/卸载栏
mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar);
// 设置应用程序视图
mAppsView = findViewById(R.id.apps_view);
mAppsView.setAllAppsTransitionController(mAllAppsController);
// 设置拖动控制器(拖动目标必须按优先级的相反顺序添加)
mDropTargetBar.setup(mDragController);
mAllAppsController.setupViews(mScrimView, mAppsView);
// 如果启用了点分页,则设置工作区的分页指示器
if (SHOW_DOT_PAGINATION.get()) {
mWorkspace.getPageIndicator().setShouldAutoHide(true);
mWorkspace.getPageIndicator().setPaintColor(
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)
? Color.BLACK
: Color.WHITE);
}
}
四、页面组件
- Workspace:工作区,也是我们常说的桌面区域,包括搜索框,桌面,壁纸。 CellLayout 是单一页。
- AppsView:应用程序列表
- Widget:小组件
Workspace(工作区)

AppsView(应用程序视图)

Widget(小组件)

4.4桌面图标排列布局
LauncherProvider.java处控制桌面图标的加载。
scss
/**
* Loads the default workspace based on the following priority scheme:
* 1) From the app restrictions
* 2) From a package provided by play store
* 3) From a partner configuration APK, already in the system image
* 4) The default configuration for the particular device
*/
synchronized private void loadDefaultFavoritesIfNecessary() {
SharedPreferences sp = Utilities.getPrefs(getContext());
if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) {
Log.d(TAG, "loading default workspace");
AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost);
if (loader == null) {
Log.d(TAG, "11111111111e");
loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper);
}
if (loader == null) {
Log.d(TAG, "11222222");
final Partner partner = Partner.get(getContext().getPackageManager());
if (partner != null && partner.hasDefaultLayout()) {
Log.d(TAG, "3333333");
final Resources partnerRes = partner.getResources();
int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
"xml", partner.getPackageName());
if (workspaceResId != 0) {
Log.d(TAG, "4444444");
loader = new DefaultLayoutParser(getContext(), widgetHost,
mOpenHelper, partnerRes, workspaceResId);
}
}
}
final boolean usingExternallyProvidedLayout = loader != null;
if (loader == null) {
Log.d(TAG, "555555");
loader = getDefaultLayoutParser(widgetHost);
}
// There might be some partially restored DB items, due to buggy restore logic in
// previous versions of launcher.
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(widgetHost));
}
clearFlagEmptyDbCreated();
}
}
非GMS版本:
要看:
Launcher3/res/xml/default_workspace**.xml 的配置。
可在device_profiles.xml 中查看配置的是哪个布局文件;go版本在 go/res/xml/device_profiles.xml
以 default_workspace_4x3.xml 为例:
xml
<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, Browser, Camera -->
<resolve
launcher:container="-101"
launcher:screen="0"
launcher:x="0"
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>
<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_GALLERY;end" />
</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_SETTINGS;end" /> -->
<favorite launcher:packageName="com.android.settings" launcher:className="com.android.settings.Settings" launcher:uri="android.settings.SETTINGS" />
</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_TURBOTEST;end" />
</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_STORE;end" />
<favorite launcher:uri="#Intent;type=images/*;end" />
</resolve>
<resolve
launcher:screen="0"
launcher:x="2"
launcher:y="-1" >
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_AGINGTEST;end" />
</resolve>
</favorites>
一个resolve中配置一个应用图标;同一个resolve 中不同的favorite是为了兼容不同版本的intent。
launcher:container="-101" 控制最下面的hotseat. 没有的是上面的快捷区。
GMS版本:
要看
vendor/google/apps/GmsSampleIntegration/***/xml/partner_default_layout.xml
中的覆盖情况。
控制应用图标隐藏
复写AppFilter 的实现类AppFilterImpl ,并配置 app_filter_class 为对应实现的类即可。
注意事项:
AppFilterImpl必须实现 带Context 参数的构造函数
scss
AppFilterImpl(Context context)
参考 Android Launcher3 隐藏应用图标和widget的显示
五、部分事件处理
5.1点击App图标的事件响应
typescript
/**
* Class for handling clicks on workspace and all-apps items
*/
public class ItemClickHandler {
private static void onClick(View v) {
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
}
// 通知launcher启动Activity
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
launcher.startActivitySafely(v, intent, item);
}
}
5.2禁用 应用长按显示信息或拖拽事件
ItemLongClickListener.java中 canStartDrag函数中返回false 即可。
5.3禁用长按空白地方弹出widget等项
在 WorkspaceTouchListener 中的 canHandleLongPress 函数中返回false 即可。