Android中Launcher解析

Ongoing,待完成,Please wait.

Launcher 概述

Launcher3代码统计:

1
2
3
4
5
6
7
8
9
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Java 354 10876 13510 57150
XML 309 1074 4971 13498
Python 2 49 31 323
-------------------------------------------------------------------------------
SUM: 665 11999 18512 70971
-------------------------------------------------------------------------------

开始学习Launcher3源码之前请务必保证你已经具备如下图所示基础知识技能(相关权重系数已经饼状图标注),如下:
"Launcher需要知识图谱"
可以形象的认为整个原生Launcher就是以MVC为宏观指导、以View为模块的结构;全局有效的核心Activity只有一个,但是其中涉及了多种交互状态,每种状态都至少依赖于一到多个庞大而复杂的自定义View,每一个事件的处理都需要考虑不同状态下不同层级、不同触摸位置的派发拦截处理流程。

其实Launcher的实质也就是一个普通应用,它只是比普通应用多配置了Category
的android:name=”android.intent.category.HOME”属性而已。当Android开机启动成功以后框架层会尝试启动包含上面属性配置的Activity,这样被启动的那个Activity就成了桌面。当我们按下设备的Home键时也会触发包含该属性的Activity。只不过当系统中只存在一个包含该属性的应用时,无论开机还是Home键触发都只会自动启动默认的;当存在多个时无论哪种触发都会弹出选择框进行选择设置。

在手机设备上我们为了保留尽可能的兼容性而没有干掉该选框,在机顶盒开发中大多数厂商为了导流和推自己的视频服务一般都会修改框架层的ActivityManagerService服务将该入口写死.

Android系统开机启动Launcher的大致过程,如下:
"Launcher启动流程"

Launcher界面的划分,如下是Launcher结构的模块划分:
"Launcher布局结构"

如下是原生Launcher3经典的四种UI模式:
"Launcher布局结构"

通过上面这两幅图可以知道,Launcher3的实质其实就是一个Activity包含N个自定义层级的View,不同模式隐藏显示不同的View而已。
参考Android M Launcher3主流程源码浅析

主要布局文件解析

下面将对一些主要的布局文件进行解析.

launcher.xml

主要类解析

下面将对上面提到的一些主要的类进行解析.

Launcher.java

主界面Activity,最核心且唯一的Activity。Launcher.java继承子BaseActivity.java,实现了一些接口,具体如下:

1
2
3
4
5
6
7
public class Launcher extends BaseActivity
implements LauncherExterns, View.OnClickListener, OnLongClickListener,
LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
AccessibilityManager.AccessibilityStateChangeListener,
WallpaperColorInfo.OnThemeChangeListener {
....
}

而BaseActivity.java继承子Activity, 包含DeviceProfile.java,UserEventDispatcher.java,SystemUiController.java

1
2
3
4
5
public abstract class BaseActivity extends Activity {
protected DeviceProfile mDeviceProfile;
protected UserEventDispatcher mUserEventDispatcher;
protected SystemUiController mSystemUiController;
}

LauncherExterns.java接口,暴露方法给其他应用调用,主要用于测试

1
2
3
4
5
6
public interface LauncherExterns {
public boolean setLauncherCallbacks(LauncherCallbacks callbacks);
public SharedPreferences getSharedPrefs();
public void setLauncherOverlay(Launcher.LauncherOverlay overlay);
void clearTypedText();
}

DeviceProfile.java

定义了Launcher中各个模块的一些基本属性.以及属性值的初始化等工作.
设置各元素布局的padding 。修改workspace的padding使用getWorkspacePadding方法。

InvariantDeviceProfile.java

一些不变的设备相关参数管理类,其内部包涵了横竖屏模式的DeviceProfile。
getPredefinedDeviceProfiles方法 负责加载在不同设备上不同的布局,和图标大小等。

SystemUiController.java

用于管理Launcher界面时,SystemUI中的StatusBar和NavigationBar的颜色

LauncherAppState.java

单例模式的全局管理类,主要是初始化一些对象,注册广播等.单例对象,构造方法中初始化对象、注册应用安装、卸载、更新,配置变化等广播。这些广播用来实时更新桌面图标等,其receiver的实现在LauncherModel类中,LauncherModel也在这里初始化。
控制和管理一下Launcher模块的大类的初始化和管理.

1
2
3
4
5
6
private final Context mContext;
private final LauncherModel mModel;
private final IconCache mIconCache;
private final WidgetPreviewLoader mWidgetCache;
private final InvariantDeviceProfile mInvariantDeviceProfile;
private final SettingsObserver mNotificationBadgingObserver;

LauncherModel.java

继承BroadcastReceiver,由此可知他是一个广播接收器,用来接收广播,另外,LauncherModel还主要加载数据;
数据处理类,保存桌面状态,提供读写数据库的API,内部类LoaderTask用来初始化桌面。

InstallShortcutReceiver.java

继承自BroadcastReceiver.

LauncherAppsCompat.java

获取已安装App列表信息的兼容抽象基类,子类依据不同版本API进行兼容性处理。
子类有LauncherAppsCompatVL.java和LauncherAppsCompatVO.java,其中LauncherAppsCompatVO处理O版本以及以上的版本.

WidgetPreviewLoader.java

存储Widget信息的数据库,内部创建了数据库widgetpreviews.db.

AppWidgetManagerCompat.java

获取AppWidget列表的兼容抽象基类,子类依据不同版本API进行兼容性处理。

LauncherStateTransitionAnimation.java

各类动画总管处理执行类,负责各种情况下的各种动画效果处理

DragLayer.java

一个用来负责分发事件的ViewGroup

DragController.java

DragLayer只是一个ViewGroup,具体的拖拽的处理都放到了DragController中。

LauncherProvider.java

继承ContentProvider,主要是处理数据库操作;
核心数据库类,负责launcher.db的创建与维护。

LauncherAppWidgetHost.java

AppWidgetHost子类,是桌面插件宿主,为了方便托拽等才继承处理的。

LauncherAppWidgetHostView.java

AppWidgetHostView子类,配合LauncherAppWidgetHost得到HostView。

LauncherRootView.java

竖屏模式下根布局,继承了InsettableFrameLayout,控制是否显示在状态栏等下面。

BubbleTextView.java

图标都基于他,继承自TextView。

DragView.java

拖动图标时跟随手指移动的View。

Floder.java

打开文件夹展示的View。

FolderIcon.java

文件夹图标.

DragSource.java/DropTarget.java

拖拽接口,DragSource表示图标从哪开始拖,DropTarget表示图标被拖到哪去。

Hotseat.java

用来放置比较常用的应用,比如拨号,短信,相机等。

WorkSpace.java

就是屏幕上左右滑的好几屏幕的容器

PageView.java

CellLayout.java

继承自ViewGroup,实现BubbleTextShadowHandler接口,
Workspace里面可以滑动的单独一屏,CellLayout负责图标和小部件的显示和整齐摆放。
mCountX 和 mCountY 分别表示 “x方向icon的个数” 和 “y方向icon的个数”
mOccupied 二维数组用来标记每个cell是否被占用,内部类CellInfo为静态类,其对象用于存储cell的基本信息。

GridOccupancy.java

用于管理每个网格的占用情况

PageIndicator.java

滑动屏幕的时候看见下方的指示器

BaseRecyclerView.java

BaseRecyclerView继承自RecyclerView,实现了RecyclerView.OnItemTouchListener.包含一个RecyclerViewFastScroller类型的变量.
处理workspace界面的左右滑动事件

AllAppsRecyclerView.java

继承自BaseRecyclerView,实现了LogContainerProvider接口.
A RecyclerView with custom fast scroll support for the all apps view.

BaseContainerView.java

抽象类

AllAppsContainerView.java

继承BaseContainerView,实现DragSource,View.OnLongClickListener, Insettable接口.
The all apps view container.

AllAppsList.java

存储所有应用程序列表
包含两个属性:

IconCache
AppFilter APP过滤,后面可以扩充AppFilter类,实现需要的过滤功能.

IconCache.java

图标缓存类,应用程序icon和title的缓存,内部类创建了数据库app_icons.db。
一个CacheEntry包含如下四个属性:

Bitmap icon 图标图片
title 图标标题
contentDescription 图标描述
isLowResIcon

AppInfo.java

Represents an app in AllAppsView.在AllApp界面呈现一个应用的APP信息.继承自ItemInfoWithIcon。
新增有四个属性:

Intent 用于启动某个APP的Intent
ComponentName 该App的组件名
isDisabled
isSystemApp 该APP是否为系统APP

LauncherActivityInfo.java

LauncherActivityInfo.java代码不在Launcher模块,在framework模块,但是在Launcher模块用的比较多,所以也放在Launcher模块一起分析.
代码路径:framework/base/core/java/android/content/pm/LauncherActivityInfo.java
A representation of an activity that can belong to this user or a managed profile associated with this user. It can be used to query the label, icon and badged icon for the activity.
包含三个属性:

ActivityInfo
ComponentName 组件信息
UserHandle 用户信息

ShortcutCache.java

快捷图标缓存

ShortcutKey.java

ShortcutKey继承自ComponentKey.通过packageName,ShortcutInfoCompat,intent,ItemInfo等方式得到快捷方式的唯一Key.

ComponentKey.java

ComponentKey包含两个属性componentName和UserHandle,实际上是将这两个属性进行了绑定,进行了一一映射.同时为了防止篡改,还对每一对分配了一个hasCode值.
同时使用Preconditions类保证线程安全.

ShortcutInfo.java

Represents a launchable icon on the workspaces and in folders.
在桌面或者文件夹里面显示的快捷方式图标.继承自ItemInfoWithIcon.
有一些标志位:

FLAG_RESTORED_ICON:此图标来自于备份,暂时还不能使用.
FLAG_AUTOINSTALL_ICON: 由自动安装的APP添加,暂时还不能使用.
FLAG_INSTALL_SESSION_ACTIVE:
FLAG_RESTORE_STARTED:
FLAG_SUPPORTS_WEB_UI:
FLAG_RESTORED_APP_TYPE:
FLAG_DISABLED_SAFEMODE:处于安全模式,该图标暂时不能使用.
FLAG_DISABLED_NOT_AVAILABLE:由于该图标的APP不能使用,使得该图标不能使用.
FLAG_DISABLED_SUSPENDED:由于该图标的APP被suspended(暂停),使得该图标不能使用.
FLAG_DISABLED_QUIET_USER:用户处于quiet mode(静音模式),使得该图标不能使用.
FLAG_DISABLED_BY_PUBLISHER:应用发布者禁用快捷方式图标,使得该图标不能使用.
FLAG_DISABLED_LOCKED_USER:当前用户被锁单,使得该图标不能使用.
新增以下属性:
isDisabled 某些情况下APP已经安装,但是快捷图标不能使用,比如:进入安全模式或者SD卡不能使用的情况下
disabledMessage 当用户尝试点击一个不能使用的图标时显示不能使用的信息.主要用于深度快捷图标.
mInstallProgress 在快捷方式中显示APP的安装进度.以百分比显示.
intent 启动APP的Intent
Intent.ShortcutIconResource
status 状态,由上面列出来的标志位来标识.

ItemInfoWithIcon.java

抽象类,继承自ItemInfo.java,Represents an ItemInfo which also holds an icon.
相对于ItemInfo增加了两个属性:

iconBitmap 储存应用的图标
usingLowResIcon 标明是否使用低资源资源图标.啥叫低资源图标,没搞懂

ItemInfo.java

Represents an item in the launcher.
包含如下属性:

itemType,itemType的类型有:ITEM_TYPE_APPLICATION,ITEM_TYPE_SHORTCUT,ITEM_TYPE_DEEP_SHORTCUT,ITEM_TYPE_FOLDER,ITEM_TYPE_APPWIDGET,ITEM_TYPE_CUSTOM_APPWIDGET.
container的种类有:CONTAINER_DESKTOP,CONTAINER_HOTSEAT
screenId 表明处于第几屏
cellX:表明第几行
cellY:表明第几列
spanX:宽度
spanY:高度
rank: 标明在一个Item列表中的位置
title: Item的名称
contentDescription: Item的描述
user: 用户

桌面上每个Item的信息数据结构,包括在第几屏、第几行、第几列、宽高等信息;该对象与数据库中记录一一对应;该类有多个子类,譬如FolderIcon的FolderInfo、BubbleTextView的ShortcutInfo等。
参见Launcher 细说ItemInfo

要理解ItemInfo,就要先理解桌面有哪几种东西,即有哪几种Item。

小工具:就是AppWidget,时钟小工具,天气小工具,等等。
快捷方式:快速启动应用的图标,一个应用可以有多个重复的快捷方式,workspace和hotseat上的都是快捷方式
文件夹:可以把多个快捷方式放到一块的,用来分类,减少屏幕空间占用。
这些东西都一些共同的,可以抽象出来的东西,有自己的宽度和高度,都有所在的位置和第几等等,而ItemInfo就是抽象出来的东西,打开ItemInfo.java,其中包含的就是这些特征,然而,最关键的是ItemInfo对象和数据库记录是一一对应的。其中有个id的成员,代表的就是数据库中ID。

对于不同的item,ItemInfo也有不同的子类,小工具对应的是LauncherAppWidgetInfo,他增加了小工具的信息(查android文档:AppWidgetProviderInfo);快捷方式对应的是ShortcutInfo,他增加了启动一个Activity所需的Intent信息;文件夹对应的是FolderInfo,他增加了文件夹是否打开的标签,文件夹内图标的信息等等。

ItemInfo的成员有几个值得说说:

container:表明图标是放在哪里的,是放在Workspace还是Hotseat,还是文件夹里面的。如果是放在Workspace上的,那么值是LauncherSettings.Favorites.CONTAINER_DESKTOP,如果是放在文件夹里面的那么container的值就是文件夹FolderInfo的id。
cellX,cellY:表明所在屏幕的哪个位置,cellY表明第几行,cellX表明第几列。如果是小工具占用多行多列的情况,就记录他左上角的位置。
spanX,spanY:宽度和高度,快捷方式和文件夹宽高都是1,小工具的宽高就要看具体情况了。
title:标题,显示应用的名字,文件夹的名字,小工具的话就不需要这个属性了。
itemType: 数据库里保存的表明这个ItemInfo具体是哪种类型的ItemInfo,启动的时候好生成具体的ItemInfo子类对象。
ItemInfo就这么多了,如果你自己看类的继承关系的话,就知道ItemInfo还有几个子类,比如AppInfo,PendingAddItemInfo,我暂时还没有搞清楚这些类的使用流程,等以后搞清楚了再加上来吧。

再说几个关于数据库的类,方便以后找代码:

LauncherProvider: 桌面信息的ContentProvider。
LauncherSettings:存了数据库相关的常量,字段名,字段常量等等。
DatabaseHelper: LaucherProvider的内部类,继承自SQLiteOpenHelper,数据库表的创建就是在它的onCreate方法里完成的。

WorkSpace左右滑动处理分析

参考Android Launcher浅析(一)

Launcher图标,Widget,文件夹等加载流程

Launcher加载图标分两种情况,
情况一:带AllApp功能的,在Workspace里面的是Shorcut快捷方式的加载
情况二:不带AllApp功能的,在Workspace里面的就是APP的ICON的方式

第一步在Launcher.java的onCreate()方法中主要完成以下几件事:
a) 壁纸颜色管理初始化,以及主题的监听
b) LauncherAppState实例化,以及通过LauncherAppState来管理的LauncherModel、IconCache等的初始化
c) View的加载和初始化
d) Widget和Drag的初始化
e) 旋转的处理
f) mModel.startLoader(currentScreen)

对于图标的加载,我们从LauncherModel.startLoader函数开始追踪.

LauncherModel
LoaderTask

Launcher图标加边框

在O版本的Launcher中,长按桌面,进入设置,有一个隐藏的开关.
打开此开关的方式:到设置里面开启开发者选项,然后重启手机,接着进入Launcher的设置界面.会出现”更改图标形状”的选项.
点击后,有默认,方形,方圆形,圆形和泪珠形可以选择.

更改图标形状 设置界面

SettingsActivity.java 里面onCreate方法中,来加载设置选项

1
2
3
4
5
6
7
8
Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE);
if (iconShapeOverride != null) {
if (IconShapeOverride.isSupported(getActivity())) {
IconShapeOverride.handlePreferenceUi((ListPreference) iconShapeOverride);
} else {
getPreferenceScreen().removePreference(iconShapeOverride);
}
}

对应的布局文件在launcher_preferences.xml中

1
2
3
4
5
6
7
8
9
10
11
12
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
......
<ListPreference
android:key="pref_override_icon_shape"
android:title="@string/icon_shape_override_label"
android:summary="%s"
android:entries="@array/icon_shape_override_paths_names"
android:entryValues="@array/icon_shape_override_paths_values"
android:defaultValue=""
android:persistent="false" />

</PreferenceScreen>

在这个xml文件中,重点关注entryValues的值,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- Values for icon shape overrides. These should correspond to entries defined
in icon_shape_override_paths_names -->
<string-array translatable="false" name="icon_shape_override_paths_values">
<item></item>
<item>M50,0L100,0 100,100 0,100 0,0z</item>
<item>M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z</item>
<item>M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0</item>
<item>M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z</item>
</string-array>

<string-array translatable="false" name="icon_shape_override_paths_names">
<!-- Option to not change the icon shape on home screen. [CHAR LIMIT=50] -->
<item>@string/icon_shape_system_default</item>
<item>@string/icon_shape_square</item>
<item>@string/icon_shape_squircle</item>
<item>@string/icon_shape_circle</item>
<item>@string/icon_shape_teardrop</item>
</string-array>

可以看到icon_shape_override_paths_values对应的是.9图的路径,通过工具可以看到上面的四种路径分别对应了图标的4中形状.

如何实现更改Launcher图标边框

从上面的布局文件可以看到.设置等处理主要是在IconShapeOverride.java中实现的.
获取当前图标形状主要是通过getAppliedValue函数获取,如下:

1
2
3
private static String getAppliedValue(Context context) {
return getDevicePrefs(context).getString(KEY_PREFERENCE, "");
}

在设置界面设置完之后,应用生效处理在apply()函数中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void apply(Context context) {
if (!Utilities.ATLEAST_OREO) {
return;
}
String path = getAppliedValue(context);
if (TextUtils.isEmpty(path)) {
return;
}
if (!isSupported(context)) {
return;
}

// magic
try {
Resources override =
new ResourcesOverride(Resources.getSystem(), getConfigResId(), path);
getSystemResField().set(null, override);
} catch (Exception e) {
Log.e(TAG, "Unable to override icon shape", e);
// revert value.
getDevicePrefs(context).edit().remove(KEY_PREFERENCE).apply();
}
}

通过查找代码,发现IconShapeOverride.apply函数在LauncherProvider.java的onCreate函数中有调用.
在IconShapeOverride里面,我们可以看到在点击完切换图标样式之后,Launcher进程会自杀.自杀完之后会重新启动.

在apply函数中,最重要的两句代码如下:

1
2
3
Resources override =
new ResourcesOverride(Resources.getSystem(), getConfigResId(), path);
getSystemResField().set(null, override);

其中ResourcesOverride代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static class ResourcesOverride extends Resources {

private final int mOverrideId;
private final String mOverrideValue;

@SuppressWarnings("deprecation")
public ResourcesOverride(Resources parent, int overrideId, String overrideValue) {
super(parent.getAssets(), parent.getDisplayMetrics(), parent.getConfiguration());
mOverrideId = overrideId;
mOverrideValue = overrideValue;
}

@NonNull
@Override
public String getString(int id) throws NotFoundException {
if (id == mOverrideId) {
return mOverrideValue;
}
return super.getString(id);
}
}

getSystemResField函数的实现如下:

1
2
3
4
5
private static Field getSystemResField() throws Exception {
Field staticField = Resources.class.getDeclaredField("mSystem");
staticField.setAccessible(true);
return staticField;
}

可以看到getSystemResField函数返回值是Field,也就是说需要通过反射来改变某个属性的值.
从代码流程上来看,是通过反射机制,将设置中的.9路径值,重新赋值给config_icon_mask这个属性.

接下来我们来看看,如何用给定的图形来给Launcher中的图标加边框.
继续从LauncherProvider开始分析.

本文讲的是开启Launcher的图标样式,实际上在Android O版本中,还可以开启系统级别的图标样式,Android O版本中系统图标样式是由 config_icon_mask 这个属性值控制,请参考为 Android 8.0 强制开启全局圆形图标规范
config_icon_mask 是在AdaptiveIconDrawable.java里面实现,也就是自适应图标,这个也是Android8.0的一个新功能.

模拟未接来电

方式一:分别读取电话和短信数据库中的相应字段
方式二:从通知里面获取(Android8.0的做法)

Android 7.0版本中的来电
通过查询发现MissCall这个通知是在Dialer里面发出,跟踪到MissedCallNotificationReceiver.java和MissedCallNotifier.java的代码,发现此通知是在收到
public static final String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = “android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION”;
这样的广播后发出.当然这个广播还会带两个参数,未接来电号码和未接来电个数.

Launcher的功能是需要显示未接来电个数就行.所以有两种方法来实现
方法一:模拟发送这个广播
方法二:调用Telecommon里面发送这个广播的方法

首先看方法一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private void sendNotificationThroughDefaultDialer(CallInfo callInfo, UserHandle userHandle) {
int count = mMissedCallCounts.get(userHandle).get();
Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle)
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT,
createClearMissedCallsPendingIntent(userHandle))
.putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, count)
.putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER,
callInfo == null ? null : callInfo.getPhoneNumber());

if (count == 1 && callInfo != null) {
final Uri handleUri = callInfo.getHandle();
String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart();

if (!TextUtils.isEmpty(handle) && !TextUtils.equals(handle,
mContext.getString(R.string.handle_restricted))) {
intent.putExtra(TelecomManager.EXTRA_CALL_BACK_INTENT,
createCallBackPendingIntent(handleUri, userHandle));
}
}


Log.w(this, "Showing missed calls through default dialer.");
mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE);
}

代码树

资源模块代码结构树如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
├── anim
│   ├── hide_popup_window.xml
│   ├── no_anim.xml
│   ├── show_popup_window.xml
│   └── task_open_enter.xml
├── animator
│   ├── all_apps_fastscroll_icon_anim.xml
│   ├── discovery_bounce.xml
│   └── overview_button_anim.xml
├── animator-v23
│   └── discovery_bounce.xml
├── color-v24
│   ├── all_apps_bg_hand_fill_dark.xml
│   └── all_apps_bg_hand_fill.xml
├── drawable
│   ├── all_apps_button_icon.xml
│   ├── all_apps_divider.xml
│   ├── all_apps_search_divider.xml
│   ├── all_apps_search_hint.xml
│   ├── bg_celllayout.xml
│   ├── deep_shortcuts_drag_handle.xml
│   ├── gutter_horizontal.xml
│   ├── horizontal_ellipsis.xml
│   ├── ic_all_apps_bg_hand.xml
│   ├── ic_all_apps_bg_icon_1.xml
│   ├── ic_all_apps_bg_icon_2.xml
│   ├── ic_all_apps_bg_icon_3.xml
│   ├── ic_all_apps_bg_icon_4.xml
│   ├── ic_allapps_search.xml
│   ├── ic_info_no_shadow.xml
│   ├── ic_instant_app_badge.xml
│   ├── ic_launcher_home.xml
│   ├── ic_remove_no_shadow.xml
│   ├── ic_setting.xml
│   ├── ic_star_rating.xml
│   ├── ic_uninstall_no_shadow.xml
│   ├── ic_wallpaper.xml
│   ├── ic_warning.xml
│   ├── ic_widget.xml
│   ├── pending_widget_bg.xml
│   ├── round_rect_primary.xml
│   └── widget_internal_focus_bg.xml
├── drawable-hdpi
...
│   ├── widget_resize_frame.9.png
│   ├── widget_resize_shadow.9.png
│   └── workspace_bg.9.png
├── drawable-mdpi
│   ├── check_theme.png
│   ├── ic_allapps.png
│   ├── ic_allapps_pressed.png
│   ├── ic_pageindicator_add_current.png
│   ├── ic_pageindicator_add.png
│   ├── ic_pageindicator_current.png
│   ├── ic_pageindicator_default.png
│   ├── ic_widget_resize_handle.png
│   ├── widget_resize_frame.9.png
│   ├── widget_resize_shadow.9.png
│   └── workspace_bg.9.png
├── drawable-v24
│   ├── ic_info_shadow.xml
│   ├── ic_remove_shadow.xml
│   └── ic_uninstall_shadow.xml
├── drawable-v26
│   ├── adaptive_icon_drawable_wrapper.xml
│   └── ic_launcher_home.xml
├── drawable-xhdpi
│   ├── check_theme.png
│   ├── ic_allapps.png
│   ├── ic_allapps_pressed.png
│   ├── ic_pageindicator_add_current.png
│   ├── ic_pageindicator_add.png
│   ├── ic_pageindicator_current.png
│   ├── ic_pageindicator_default.png
│   ├── ic_widget_resize_handle.png
│   ├── widget_resize_frame.9.png
│   ├── widget_resize_shadow.9.png
│   └── workspace_bg.9.png
├── drawable-xxhdpi
│   ├── check_theme.png
│   ├── ic_allapps.png
│   ├── ic_allapps_pressed.png
│   ├── ic_pageindicator_add_current.png
│   ├── ic_pageindicator_add.png
│   ├── ic_pageindicator_current.png
│   ├── ic_pageindicator_default.png
│   ├── ic_widget_resize_handle.png
│   ├── widget_resize_frame.9.png
│   ├── widget_resize_shadow.9.png
│   └── workspace_bg.9.png
├── drawable-xxxhdpi
│   ├── check_theme.png
│   ├── ic_widget_resize_handle.png
│   ├── widget_resize_frame.9.png
│   ├── widget_resize_shadow.9.png
│   └── workspace_bg.9.png
├── interpolator
│   ├── decelerate_quart.xml
│   ├── decelerate_quint.xml
│   ├── disco_bounce.xml
│   ├── folder_interpolator.xml
│   ├── large_folder_preview_item_close_interpolator.xml
│   └── large_folder_preview_item_open_interpolator.xml
├── layout
│   ├── add_item_confirmation_activity.xml
│   ├── all_apps_button.xml
│   ├── all_apps_discovery_item.xml
│   ├── all_apps_discovery_loading_divider.xml
│   ├── all_apps_divider.xml
│   ├── all_apps_empty_search.xml
│   ├── all_apps_fast_scroller.xml
│   ├── all_apps_icon.xml
│   ├── all_apps_search_market.xml
│   ├── all_apps.xml
│   ├── app_icon.xml
│   ├── appwidget_error.xml
│   ├── appwidget_not_ready.xml
│   ├── app_widget_resize_frame.xml
│   ├── deep_shortcut.xml
│   ├── drop_target_bar_horz.xml
│   ├── drop_target_bar_vert.xml
│   ├── folder_application.xml
│   ├── folder_icon.xml
│   ├── folder_page.xml
│   ├── gradient_bg.xml
│   ├── hotseat.xml
│   ├── notification_footer.xml
│   ├── notification_main.xml
│   ├── notification_pref_warning.xml
│   ├── notification.xml
│   ├── overview_panel.xml
│   ├── page_indicator_marker.xml
│   ├── page_indicator_point.xml
│   ├── page_indicator.xml
│   ├── popup_container.xml
│   ├── popup_window.xml
│   ├── qsb_default_view.xml
│   ├── search_container_all_apps.xml
│   ├── search_container_workspace.xml
│   ├── shortcuts_item.xml
│   ├── system_shortcut_icon_only.xml
│   ├── system_shortcut_icons.xml
│   ├── system_shortcut.xml
│   ├── theme_item.xml
│   ├── theme.xml
│   ├── user_folder_icon_normalized.xml
│   ├── user_folder.xml
│   ├── widget_cell_content.xml
│   ├── widget_cell.xml
│   ├── widget_list_divider.xml
│   ├── widgets_bottom_sheet.xml
│   ├── widgets_list_row_view.xml
│   ├── widgets_scroll_container.xml
│   ├── widgets_view.xml
│   ├── workspace_screen.xml
│   ├── zzz_dummy_widget.xml
│   └── zzz_weight_watcher.xml
├── layout-land
│   ├── all_apps_fast_scroller.xml
│   └── launcher.xml
├── layout-port
│   └── launcher.xml
├── layout-sw720dp
│   ├── all_apps_fast_scroller.xml
│   └── launcher.xml
├── mipmap-hdpi
│   ├── ic_launcher_home_foreground.png
│   └── ic_launcher_home.png
├── mipmap-mdpi
│   ├── ic_launcher_home_foreground.png
│   └── ic_launcher_home.png
├── mipmap-xhdpi
│   ├── ic_launcher_home_foreground.png
│   └── ic_launcher_home.png
├── mipmap-xxhdpi
│   ├── ic_launcher_home_foreground.png
│   └── ic_launcher_home.png
├── raw
│   └── downgrade_schema.json
├── values
│   ├── arrays.xml
│   ├── attrs.xml
│   ├── bools.xml
│   ├── colors.xml
│   ├── config.xml
│   ├── dimens.xml
│   ├── drawables.xml
│   ├── strings.xml
│   └── styles.xml
......
├── values-zh-rCN
│   └── strings.xml
├── values-zh-rHK
│   └── strings.xml
├── values-zh-rTW
│   └── strings.xml
└── xml
├── backupscheme.xml
├── default_workspace_3x3.xml
├── default_workspace_4x4.xml
├── default_workspace_5x5.xml
├── default_workspace_5x6.xml
├── device_profiles.xml
├── dw_phone_hotseat.xml
├── dw_tablet_hotseat.xml
└── launcher_preferences.xml

Java模块的代码结构树如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
├── src
│   └── com
│   └── android
│   └── launcher3
│   ├── AbstractFloatingView.java
│   ├── accessibility
│   │   ├── AccessibleDragListenerAdapter.java
│   │   ├── DragAndDropAccessibilityDelegate.java
│   │   ├── DragViewStateAnnouncer.java
│   │   ├── FolderAccessibilityHelper.java
│   │   ├── LauncherAccessibilityDelegate.java
│   │   ├── OverviewAccessibilityDelegate.java
│   │   ├── OverviewScreenAccessibilityDelegate.java
│   │   ├── ShortcutMenuAccessibilityDelegate.java
│   │   └── WorkspaceAccessibilityHelper.java
│   ├── Alarm.java
│   ├── allapps
│   │   ├── AllAppsBackgroundDrawable.java
│   │   ├── AllAppsCaretController.java
│   │   ├── AllAppsContainerView.java
│   │   ├── AllAppsFastScrollHelper.java
│   │   ├── AllAppsGridAdapter.java
│   │   ├── AllAppsRecyclerViewContainerView.java
│   │   ├── AllAppsRecyclerView.java
│   │   ├── AllAppsTransitionController.java
│   │   ├── AlphabeticalAppsList.java
│   │   ├── AppInfoComparator.java
│   │   ├── LandscapeFastScroller.java
│   │   ├── search
│   │   │   ├── AllAppsSearchBarController.java
│   │   │   ├── AppsSearchContainerLayout.java
│   │   │   ├── DefaultAppSearchAlgorithm.java
│   │   │   ├── HeaderElevationController.java
│   │   │   └── SearchAlgorithm.java
│   │   └── SearchUiManager.java
│   ├── AllAppsList.java
│   ├── anim
│   │   ├── AnimationLayerSet.java
│   │   ├── CircleRevealOutlineProvider.java
│   │   ├── PropertyListBuilder.java
│   │   ├── PropertyResetListener.java
│   │   ├── RevealOutlineAnimation.java
│   │   ├── RoundedRectRevealOutlineProvider.java
│   │   └── SpringAnimationHandler.java
│   ├── AppFilter.java
│   ├── AppInfo.java
│   ├── AppWidgetResizeFrame.java
│   ├── AppWidgetsRestoredReceiver.java
│   ├── AutoInstallsLayout.java
│   ├── badge
│   │   ├── BadgeInfo.java
│   │   ├── BadgeRenderer.java
│   │   └── FolderBadgeInfo.java
│   ├── BaseActivity.java
│   ├── BaseContainerView.java
│   ├── BaseRecyclerView.java
│   ├── BubbleTextView.java
│   ├── ButtonDropTarget.java
│   ├── CellLayout.java
│   ├── CheckLongPressHelper.java
│   ├── ClickShadowView.java
│   ├── compat
│   │   ├── AlphabeticIndexCompat.java
│   │   ├── AppWidgetManagerCompat.java
│   │   ├── AppWidgetManagerCompatVL.java
│   │   ├── AppWidgetManagerCompatVO.java
│   │   ├── LauncherAppsCompat.java
│   │   ├── LauncherAppsCompatVL.java
│   │   ├── LauncherAppsCompatVO.java
│   │   ├── PackageInstallerCompat.java
│   │   ├── PackageInstallerCompatVL.java
│   │   ├── ShortcutConfigActivityInfo.java
│   │   ├── UserManagerCompat.java
│   │   ├── UserManagerCompatVL.java
│   │   ├── UserManagerCompatVM.java
│   │   ├── UserManagerCompatVN.java
│   │   ├── UserManagerCompatVNMr1.java
│   │   ├── WallpaperColorsCompat.java
│   │   ├── WallpaperManagerCompat.java
│   │   ├── WallpaperManagerCompatVL.java
│   │   └── WallpaperManagerCompatVOMR1.java
│   ├── config
│   │   └── BaseFlags.java
│   ├── CustomAppWidget.java
│   ├── DefaultLayoutParser.java
│   ├── DeleteDropTarget.java
│   ├── DeviceProfile.java
│   ├── discovery
│   │   ├── AppDiscoveryAppInfo.java
│   │   ├── AppDiscoveryItem.java
│   │   ├── AppDiscoveryItemView.java
│   │   ├── AppDiscoveryUpdateState.java
│   │   └── RatingView.java
│   ├── dragndrop
│   │   ├── AddItemActivity.java
│   │   ├── BaseItemDragListener.java
│   │   ├── DragController.java
│   │   ├── DragDriver.java
│   │   ├── DragLayer.java
│   │   ├── DragOptions.java
│   │   ├── DragView.java
│   │   ├── FlingToDeleteHelper.java
│   │   ├── FolderAdaptiveIcon.java
│   │   ├── LivePreviewWidgetCell.java
│   │   ├── PinItemDragListener.java
│   │   ├── PinShortcutRequestActivityInfo.java
│   │   ├── PinWidgetFlowHandler.java
│   │   └── SpringLoadedDragController.java
│   ├── DragSource.java
│   ├── DropTargetBar.java
│   ├── DropTarget.java
│   ├── dynamicui
│   │   ├── ColorExtractionAlgorithm.java
│   │   ├── ColorExtractionService.java
│   │   ├── ExtractedColors.java
│   │   ├── ExtractionUtils.java
│   │   └── WallpaperColorInfo.java
│   ├── ExtendedEditText.java
│   ├── FastBitmapDrawable.java
│   ├── FirstFrameAnimatorHelper.java
│   ├── FocusHelper.java
│   ├── folder
│   │   ├── ClippedFolderIconLayoutRule.java
│   │   ├── FolderAnimationManager.java
│   │   ├── FolderIcon.java
│   │   ├── FolderIconPreviewVerifier.java
│   │   ├── Folder.java
│   │   ├── FolderPagedView.java
│   │   ├── FolderPreviewItemAnim.java
│   │   ├── PreviewBackground.java
│   │   ├── PreviewImageView.java
│   │   ├── PreviewItemDrawingParams.java
│   │   ├── PreviewItemManager.java
│   │   └── StackFolderIconLayoutRule.java
│   ├── FolderInfo.java
│   ├── graphics
│   │   ├── DragPreviewProvider.java
│   │   ├── DrawableFactory.java
│   │   ├── FastScrollThumbDrawable.java
│   │   ├── FixedScaleDrawable.java
│   │   ├── GradientView.java
│   │   ├── HolographicOutlineHelper.java
│   │   ├── IconNormalizer.java
│   │   ├── IconPalette.java
│   │   ├── IconShapeOverride.java
│   │   ├── LauncherIcons.java
│   │   ├── PreloadIconDrawable.java
│   │   ├── ShadowDrawable.java
│   │   ├── ShadowGenerator.java
│   │   ├── TintedDrawableSpan.java
│   │   └── TriangleShape.java
│   ├── Hotseat.java
│   ├── IconCache.java
│   ├── IconProvider.java
│   ├── InfoDropTarget.java
│   ├── InsettableFrameLayout.java
│   ├── Insettable.java
│   ├── InstallShortcutReceiver.java
│   ├── InterruptibleInOutAnimator.java
│   ├── InvariantDeviceProfile.java
│   ├── ItemInfo.java
│   ├── ItemInfoWithIcon.java
│   ├── keyboard
│   │   ├── CustomActionsPopup.java
│   │   ├── FocusedItemDecorator.java
│   │   ├── FocusIndicatorHelper.java
│   │   └── ViewGroupFocusHelper.java
│   ├── LauncherAnimUtils.java
│   ├── LauncherAppState.java
│   ├── LauncherAppWidgetHost.java
│   ├── LauncherAppWidgetHostView.java
│   ├── LauncherAppWidgetInfo.java
│   ├── LauncherAppWidgetProviderInfo.java
│   ├── LauncherBackupAgent.java
│   ├── LauncherCallbacks.java
│   ├── LauncherExterns.java
│   ├── LauncherFiles.java
│   ├── Launcher.java
│   ├── LauncherModel.java
│   ├── LauncherProviderChangeListener.java
│   ├── LauncherProvider.java
│   ├── LauncherRootView.java
│   ├── LauncherScroller.java
│   ├── LauncherSettings.java
│   ├── LauncherStateTransitionAnimation.java
│   ├── LogAccelerateInterpolator.java
│   ├── LogDecelerateInterpolator.java
│   ├── logging
│   │   ├── DumpTargetWrapper.java
│   │   ├── FileLog.java
│   │   ├── LoggerUtils.java
│   │   └── UserEventDispatcher.java
│   ├── MainThreadExecutor.java
│   ├── model
│   │   ├── AddWorkspaceItemsTask.java
│   │   ├── BaseModelUpdateTask.java
│   │   ├── BgDataModel.java
│   │   ├── CacheDataUpdatedTask.java
│   │   ├── DbDowngradeHelper.java
│   │   ├── GridSizeMigrationTask.java
│   │   ├── LoaderCursor.java
│   │   ├── LoaderResults.java
│   │   ├── LoaderTask.java
│   │   ├── ModelWriter.java
│   │   ├── PackageInstallStateChangedTask.java
│   │   ├── PackageItemInfo.java
│   │   ├── PackageUpdatedTask.java
│   │   ├── SdCardAvailableReceiver.java
│   │   ├── ShortcutsChangedTask.java
│   │   ├── UserLockStateChangedTask.java
│   │   ├── WidgetItem.java
│   │   └── WidgetsModel.java
│   ├── notification
│   │   ├── Interpolators.java
│   │   ├── NotificationFooterLayout.java
│   │   ├── NotificationInfo.java
│   │   ├── NotificationItemView.java
│   │   ├── NotificationKeyData.java
│   │   ├── NotificationListener.java
│   │   └── NotificationMainView.java
│   ├── OnAlarmListener.java
│   ├── OverviewButtonClickListener.java
│   ├── PagedView.java
│   ├── pageindicators
│   │   ├── CaretDrawable.java
│   │   ├── PageIndicatorCaretLandscape.java
│   │   ├── PageIndicatorDots.java
│   │   ├── PageIndicator.java
│   │   ├── PageIndicatorLineCaret.java
│   │   ├── PageIndicatorMarker.java
│   │   └── PageIndicatorPoint.java
│   ├── Partner.java
│   ├── PendingAddItemInfo.java
│   ├── PendingAppWidgetHostView.java
│   ├── PinchAnimationManager.java
│   ├── PinchThresholdManager.java
│   ├── PinchToOverviewListener.java
│   ├── popup
│   │   ├── PopupContainerWithArrow.java
│   │   ├── PopupDataProvider.java
│   │   ├── PopupItemView.java
│   │   ├── PopupPopulator.java
│   │   └── SystemShortcut.java
│   ├── PromiseAppInfo.java
│   ├── provider
│   │   ├── ImportDataTask.java
│   │   ├── LauncherDbUtils.java
│   │   ├── LossyScreenMigrationTask.java
│   │   └── RestoreDbTask.java
│   ├── qsb
│   │   ├── QsbContainerView.java
│   │   └── QsbWidgetHostView.java
│   ├── SessionCommitReceiver.java
│   ├── SettingsActivity.java
│   ├── ShortcutAndWidgetContainer.java
│   ├── ShortcutInfo.java
│   ├── shortcuts
│   │   ├── DeepShortcutManager.java
│   │   ├── DeepShortcutTextView.java
│   │   ├── DeepShortcutView.java
│   │   ├── ShortcutCache.java
│   │   ├── ShortcutDragPreviewProvider.java
│   │   ├── ShortcutInfoCompat.java
│   │   ├── ShortcutKey.java
│   │   └── ShortcutsItemView.java
│   ├── SimpleOnStylusPressListener.java
│   ├── StylusEventHelper.java
│   ├── testing
│   │   ├── DummyWidget.java
│   │   ├── LauncherExtension.java
│   │   ├── MemoryDumpActivity.java
│   │   ├── MemoryTracker.java
│   │   ├── ToggleWeightWatcher.java
│   │   └── WeightWatcher.java
│   ├── theme
│   │   ├── LocalThemeFragment.java
│   │   ├── LocalThemeUtils.java
│   │   ├── ProgressView.java
│   │   └── ThemeUpdateTask.java
│   ├── touch
│   │   ├── OverScroll.java
│   │   └── SwipeDetector.java
│   ├── UninstallDropTarget.java
│   ├── util
│   │   ├── ActivityResultInfo.java
│   │   ├── CellAndSpan.java
│   │   ├── ComponentKey.java
│   │   ├── ComponentKeyMapper.java
│   │   ├── ConfigMonitor.java
│   │   ├── ContentWriter.java
│   │   ├── FlagOp.java
│   │   ├── FlingAnimation.java
│   │   ├── FocusLogic.java
│   │   ├── GridOccupancy.java
│   │   ├── InstantAppResolver.java
│   │   ├── IOUtils.java
│   │   ├── ItemInfoMatcher.java
│   │   ├── LabelComparator.java
│   │   ├── LogConfig.java
│   │   ├── LongArrayMap.java
│   │   ├── LooperExecutor.java
│   │   ├── LooperIdleLock.java
│   │   ├── ManagedProfileHeuristic.java
│   │   ├── MultiHashMap.java
│   │   ├── NoLocaleSqliteContext.java
│   │   ├── PackageManagerHelper.java
│   │   ├── PackageUserKey.java
│   │   ├── ParcelableSparseArray.java
│   │   ├── PendingRequestArgs.java
│   │   ├── Preconditions.java
│   │   ├── Provider.java
│   │   ├── RunnableWithId.java
│   │   ├── SettingsObserver.java
│   │   ├── SQLiteCacheHelper.java
│   │   ├── SystemUiController.java
│   │   ├── TestingUtils.java
│   │   ├── Themes.java
│   │   ├── Thunk.java
│   │   ├── TouchController.java
│   │   ├── TransformingTouchDelegate.java
│   │   ├── VerticalFlingDetector.java
│   │   ├── ViewOnDrawExecutor.java
│   │   └── WallpaperOffsetInterpolator.java
│   ├── Utilities.java
│   ├── views
│   │   ├── ButtonPreference.java
│   │   ├── DoubleShadowBubbleTextView.java
│   │   └── RecyclerViewFastScroller.java
│   ├── widget
│   │   ├── PendingAddShortcutInfo.java
│   │   ├── PendingAddWidgetInfo.java
│   │   ├── PendingItemDragHelper.java
│   │   ├── WidgetAddFlowHandler.java
│   │   ├── WidgetCell.java
│   │   ├── WidgetHostViewLoader.java
│   │   ├── WidgetImageView.java
│   │   ├── WidgetItemComparator.java
│   │   ├── WidgetListRowEntry.java
│   │   ├── WidgetsBottomSheet.java
│   │   ├── WidgetsContainerView.java
│   │   ├── WidgetsDiffReporter.java
│   │   ├── WidgetsListAdapter.java
│   │   ├── WidgetsRecyclerView.java
│   │   └── WidgetsRowViewHolder.java
│   ├── WidgetPreviewLoader.java
│   ├── Workspace.java
│   └── WorkspaceStateTransitionAnimation.java
├── src_config
│   └── com
│   └── android
│   └── launcher3
│   └── BuildConfig.java
├── src_flags
│   └── com
│   └── android
│   └── launcher3
│   └── config
│   └── FeatureFlags.java
└── tests
├── AndroidManifest-common.xml
│   ├── raw
│   │   ├── cache_data_updated_task_data.txt
│   │   ├── db_schema_v10.json
│   │   └── package_install_state_change_task_data.txt
│   └── xml
│   ├── appwidget_no_config.xml
│   └── appwidget_with_config.xml
└── src
└── com
└── android
└── launcher3
├── allapps
│   └── search
│   └── DefaultAppSearchAlgorithmTest.java
├── logging
│   └── FileLogTest.java
├── model
│   ├── AddWorkspaceItemsTaskTest.java
│   ├── BaseModelUpdateTaskTestCase.java
│   ├── CacheDataUpdatedTaskTest.java
│   ├── DbDowngradeHelperTest.java
│   ├── GridSizeMigrationTaskTest.java
│   ├── LoaderCursorTest.java
│   └── PackageInstallStateChangedTaskTest.java
├── popup
│   └── PopupPopulatorTest.java
├── provider
│   └── RestoreDbTaskTest.java
├── testcomponent
│   ├── AppWidgetNoConfig.java
│   ├── AppWidgetWithConfig.java
│   ├── BaseTestingActivity.java
│   ├── RequestPinItemActivity.java
│   ├── TouchEventGenerator.java
│   └── WidgetConfigActivity.java
├── touch
│   └── SwipeDetectorTest.java
├── ui
│   ├── AbstractLauncherUiTest.java
│   ├── AllAppsAppLaunchTest.java
│   ├── AllAppsIconToHomeTest.java
│   ├── ShortcutsLaunchTest.java
│   ├── ShortcutsToHomeTest.java
│   └── widget
│   ├── AddConfigWidgetTest.java
│   ├── AddWidgetTest.java
│   ├── BindWidgetTest.java
│   └── RequestPinItemTest.java
├── util
│   ├── Condition.java
│   ├── FocusLogicTest.java
│   ├── GridOccupancyTest.java
│   ├── rule
│   │   ├── LauncherActivityRule.java
│   │   └── ShellCommandRule.java
│   ├── TestLauncherProvider.java
│   └── Wait.java
└── widget
└── WidgetsListAdapterTest.java

参考文献

Android M Launcher3主流程源码浅析 ★★★★★

Android Launcher浅析(一) workspace左右滑动处理

android launcher 全面解析 可以参考一下

Android7.0 启动Launcher流程 Launcher启动流程可以参考

Android M 6.0 Launcher3 动态改变日历图标

Launcher 细说ItemInfo

一步步客制化Android桌面(Launcher3)图标 可以用此思路来更改主题

Android Launcher分析和修改 系列文章

墨香带你学Launcher之(一)- 概述 讲述了Launcher的布局界面等基本东西
墨香带你学Launcher之(二)- 数据加载流程
讲解了Launcher桌面图标的默认配置
Launcher从AMS启动的流程
Launcher的初始化流程
Launcher的数据加载
墨香带你学Launcher之(三)- 绑定屏幕、图标、文件夹和Widget
墨香带你学Launcher之(四)- 应用安装、更新、卸载时的数据加载
墨香带你学Launcher之(五)- Workspace滑动
墨香带你学Launcher之(六)- 拖拽
墨香带你学Launcher之(七)- 小部件的加载、添加以及大小调节
墨香带你学Launcher之(八)- 加载Icon、设置壁纸

Android原生Launcher3简要分析

Android8.1 Launcher3 去掉抽屉(一)
Android8.1 Launcher3 去掉抽屉(二)
Android8.1 Launcher3 去掉抽屉(三)

Android 7.0 Launcher3 去掉应用抽屉