Android中Launcher解析

Launcher 概述

Launcher3代码统计:

-------------------------------------------------------------------------------
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,实现了一些接口,具体如下:

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

public abstract class BaseActivity extends Activity {
protected DeviceProfile mDeviceProfile;
protected UserEventDispatcher mUserEventDispatcher;
protected SystemUiController mSystemUiController;
}

 

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

public interface LauncherExterns {
public boolean setLauncherCallbacks(LauncherCallbacks callbacks);
public SharedPreferences getSharedPrefs();
public void setLauncherOverlay(Launcher.LauncherOverlay overlay);
void clearTypedText();
}

 

Launcher.java:
launcher中主要的activity。 LoaderTask.java:
可运行用于加载启动器内容的线程: 工作区图标 、小部件 、所有应用程序图标 、应用程序快捷方式。 LauncherAppState.java:
用于存储全局变量,比如:缓存(各种cache),维护内存数据的类(LauncherModel)。 DragLayer.java:
launcher layout的rootview。DragLayer实际上也是一个抽象的界面,用来处理拖动和对事件进行初步处理然后按情况分发下去,角色是一个controller。
它首先用onInterceptTouchEvent(MotionEvent)来拦截所有的touch事件,如果是长按item拖动的话不把事件传下去,直接交由onTouchEvent()处理,
这样就可以实现item的移动了,如果不是拖动item的话就把事件传到目标view,交有目标view的事件处理函数做相应处理。如过有要对事件的特殊需求的话可以
修改onInterceptTouchEvent(MotionEvent)来实现所需要的功能。 DragController.java:
为Drag定义的一个接口。包含一个接口,两个方法和两个静态常量。接口为DragListener(包含onDragStart(),onDragEnd()两个函数),onDragStart()是在刚开始拖动的时候被调用,
onDragEnd()是在拖动完成时被调用。在launcher中典型的应用是DeleteZone,在长按拖动item时调用onDragStart()显示,在拖动结束的时候onDragEnd()隐藏。两个函数包括startDrag()
和setDragItemInfo().startDrag()用于在拖动是传递要拖动的item的信息以及拖动的方式,setDragItemInfo()用于传递item的参数信息(包括位置以及大小)。
两个常量为DRAG_ACTION_MOVE,DRAG_ACTION_COPY来标识拖动的方式,DRAG_ACTION_MOVE为移动,表示在拖动的时候需要删除原来的item,DRAG_ACTION_COPY为复制型的拖动,
表示保留被拖动的item。 LauncherModel.java:
辅助的文件。里面有许多封装的对数据库的操作。包含几个线程,其中最主要的是ApplicationsLoader和DesktopItemsLoader。ApplicationsLoader在加载所有应用程序时使用,
DesktopItemsLoader在加载workspace的时候使用。其他的函数就是对数据库的封装,比如在删除,替换,添加程序的时候做更新数据库和UI的工作。 Workspace.java:
抽象的桌面。由N个celllaout组成,从cellLayout更高一级的层面上对事件的处理。 LauncherProvider.java:
launcher的数据库,里面存储了桌面的item的信息。在创建数据库的时候会loadFavorites(db)方法,loadFavorites()会解析xml目录下的default_workspace.xml文件,
把其中的内容读出来写到数据库中,这样就做到了桌面的预制。 CellLayout.java:
组成workspace的view,继承自viewgroup,既是一个dragSource,又是一个dropTarget,可以将它里面的item拖出去,也可以容纳拖动过来的item。
在workspace_screen里面定了一些它的view参数。 ItemInfo.java:
对item的抽象,所有类型item的父类,item包含的属性有id(标识item的id),cellX(在横向位置上的位置,从0开始),cellY(在纵向位置上的位置,从0开始) ,
spanX(在横向位置上所占的单位格),spanY(在纵向位置上所占的单位格),screen(在workspace的第几屏,从0开始),itemType(item的类型,有widget,search,application等),
container(item所在的)。
LauncherSettings.java:
字符串的定义。数据库项的字符串定义,另外在这里定义了container的类型,还有itemType的定义,除此还有一些特殊的widget(如search,clock的定义等)的类型定义。

 

 

 

DeviceProfile.java

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

InvariantDeviceProfile.java

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

SystemUiController.java

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

LauncherAppState.java

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

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方法中,来加载设置选项

Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE);
if (iconShapeOverride != null) {
if (IconShapeOverride.isSupported(getActivity())) {
IconShapeOverride.handlePreferenceUi((ListPreference) iconShapeOverride);
} else {
getPreferenceScreen().removePreference(iconShapeOverride);
}
}

 

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

<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的值,如下:

<!-- 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函数获取,如下:

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

 

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

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函数中,最重要的两句代码如下:

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

 

其中ResourcesOverride代码如下:

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函数的实现如下:

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里面发送这个广播的方法

首先看方法一:

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);
}

代码树

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

├── 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模块的代码结构树如下:

├── 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
posted @   最好不过如今  阅读(295)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示