Launcher3分析及定制&主题实现

一. Launcher3 简介

**launcher3是在Launcher2的基础上进化的版本,从Android 4.4 开始就使用Launcher3 .(kk版,kk2版)作为桌面使用,以前我们都在使用Launcher2,我们使用的是KK版本,具体区别后面再说. **

  1. 1 Launcher3 桌面变成了动态管理,launcher2 里面默认最多加载五个workspace布局.
    Launcher3分析及定制&主题实现_第1张图片
    1.2 Launcher3 提供了类似小米的只有Workspace桌面机制.
    1.3 增加了可以调整workspace页面的前后顺序
    1.4 默认不支持预置APPWidget,需要用户指定权限.

1.5 默认不支持预置APPWidget,需要用户指定权限.

在目前Launcher3 的架构上,会有些客至化受限制或者存在bug.

2.1 无法预置空白的workspace页面,主要是与动态增减页面数量相冲突.
2.2 如果预置workspace页面大于一页,无法指定非第一页为主页面,主要是与动态增减页面数量相冲突,导致Exception;
2.3 安装到SD卡的应用,桌面创建快截图标后,关机再开机如果SD卡挂载慢,桌面快截图标会消失,包括Folder中图标也类试,这是Google Default 设计.
2.4 Launcher2 循环滑动功能在Launcher3 bug很多无法解决,主要由于Launcher3 Workspace结构大修改,目前无法做到有效的循环滑动,Launcher3暂时不支持.
#二.Launcher3 启动流程:

Launcher3分析及定制&主题实现_第2张图片

Launcher3分析及定制&主题实现_第3张图片

Activity Manager通过发送Intend来启动Launcher。
Intent intent = new Intent(mTopAction, mTopData != null ? 
Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); 
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL){ 
 intent.addCategory(Intent.CATEGORY_HOME); 
}
startActivityLocked(null, intent, null, null, 0, aInfo, null, null, 0, 0, 0, false, false); 
因此,如果你要开机启动一个替换Launcher的程序,只要在程序里面加入action.MAIN 、category.HOME、category.DEFAULT就可以。如果出现多个程序都加入这种intent,系统会弹出让你选择哪个作为启动器。```

##Launcher3 初始化:、

1.1 Launcher2初始化判断屏幕大小 屏幕密度以及BroadcastReceive和ContentObserver的注册都在整个程序的开始就完成了,是在LauncherApplication.java 里面,Launcher3 封装到了LauncherAppState里面了,在LauncherApplication.java里面获取实例.
1.2 然后就是初始化Launcher.java类 初始化加载预置apk
Widget.
LauncherProvider: Launcher的数据库,一个contentprovider里面存储了桌面的item信息, loadFavorites()会解析xml 目录下的default_workspace.xml文件,把读出来的内容写到数据库中,这样就做到了桌面的预置.
在default_workspace.xml中加载我们需要定制的apk,widget :
预置Widget:

Launcher3分析及定制&主题实现_第4张图片
如果widget需要的宽度大于Launcher 桌面配置的n 个cell格子宽度,这个widget就无法再Launcher的列表显示.
需要注意的:就是widget的类名.继承的是 AppWidgetProvider
预置apk :

Launcher3分析及定制&主题实现_第5张图片

##数据流程加载:
Launcher3 数据加载是从Launcher类的onCreat()方法开始执行.

Launcher3分析及定制&主题实现_第6张图片

情况一: 用户离开Launchre页面,采用异步加载
情况二: Launcher 在前台,用户旋转了屏幕,采用同步加载.
两种情况都调用了LauncherModel类的startLoader()方法
startLoader() 函数的核心代码是线程类LoaderTask,该类中有两条路径进行应用数据的加载,其中一个路径就是:
runBindSynchronousPage()//重新加载桌面的应用
另一个路径就是LoaderTask 线程类的Run()方法中.
先是执行loadAndBindWorkspace()方法进行workspace的加载,然后执行loadAndBindAllApps()方法进行所有的app的加载。
所有的数据都都围绕着LauncherModel ,Launcher类实现了callback回调接口.
bindWorkspace的过程如下:
Launcher3分析及定制&主题实现_第7张图片

回调接口:

public interface Callbacks {
public boolean setLoadOnResume();
public int getCurrentWorkspaceScreen();
public void startBinding();
public void bindItems(ArrayList shortcuts, int start, int end, boolean forceAnimateIcons);
public void bindScreens(ArrayList orderedScreenIds);
public void bindAddScreens(ArrayList orderedScreenIds);
public void bindFolders(HashMap folders);
public void finishBindingItems(boolean upgradePath);
public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList apps);
public void bindAppsAdded(ArrayList newScreens, ArrayList addNotAnimated, ArrayList addAnimated, ArrayList addedApps);
public void bindAppsUpdated(ArrayList apps);
public void bindComponentsRemoved(ArrayList packageNames, ArrayList appInfos, boolean matchPackageNamesOnly);
public void bindPackagesUpdated(ArrayList widgetsAndShortcuts);
public void bindSearchablesChanged();
public boolean isAllAppsButtonRank(int rank);
public void onPageBoundSynchronously(int page);
public void dumpLogsToLocalData();
	}

setLoadOnResume()     由于Launcher继承自Activity,因此Launcher可能会处于paused状态(onPause()被调用),则有可能在这段时间内资源可能发生了改变,如应用被删除或新应用安装,因此需要在onResume()中调用此方法进行重新加载。
getCurrentWorkspace()    获取当前屏幕的序号
startBinding()     通知Launcher加载开始,并更新Workspace上的shortcuts
bindItems(ArrayList shortcuts, int start, int end)     加载一批内容项到Workspace,加载的内容项包括,Application、shortcut、folder。
bindFolders(HashMap folders)    加载folder的内容
finishBindingItems()    通知Launcher加载结束。
bindAppWidget(LauncherAppWidgetInfo item)    加载AppWidget到Workspace
bindAllApplications(final ArrayList apps)   在All Apps页加载所有应用的Icon
bindAppsAdded(ArrayList apps)   通知Launcher一个新的应用被安装,并加载这个应用
bindAppsUpdated(ArrayList apps)  通知Launcher一个应用发生了更新
bindAppsRemoved(ArrayList apps, boolean permanent)    通知Launcher一个应用被删除了
bindPackagesUpdated()   通知Launcher多个应用发生了更新
isAllAppsVisible()用于在加载的过程中记录当前Launcher的状态,返回true则当前显示的All Apps
bindSearchablesChanged()当搜索/删除框状态发生改变时调用
loadAndBindWorkspace:workspace的加载。
loadAndBindAllApps:allApps的加载

Launcher3 定制修改.

1.Launcher3 本身就有具有实现单层的功能:
kk版本要实现单层:
AppsCustomizePagedView.Java中 DISABLE_ALL_APPS== false ,只需修改为 true 即可.
kk2版本要实现单层:
LauncherAppState.java 中 isDisableAllApps() 返回 true 隐藏,返回 false 显示.
2. 屏幕适配 :
Launcher3 中直接是在 DynamicGrid.Java 类中,匹配屏幕的大小;

Launcher3分析及定制&主题实现_第8张图片
主要参数含义:
设备名、最小宽度Dps、最小高度Dps、行数、列数、图标大小、图标字体大小、固定热键数目(Hotseat)、固定热键图标大小
DynamicGrid.Java :
有个Layout()方法:中对search bar ,workspace, hotseat ,进行排列,如果我们需要改变大小,就直接在这个类中修改.
设置workspace大小:

Launcher3分析及定制&主题实现_第9张图片
#####隐藏Hotseat (xml中注掉控件)
去掉hotseat 相关的类,含有hotseat相关代码.
Launcher.java 直接设置为null

Workspce.java 直接注掉 getUniqueIntents((CellLayout)mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, false);
LauncherModel.java //会报异常注掉

DynamincGrid.java

Launcher3分析及定制&主题实现_第10张图片

Workspace .java 中禁止掉文件夹生成, 在onDrop()方法中处理:

Launcher3分析及定制&主题实现_第11张图片

Launcher.java 中禁止workspace长按事件,在onLongClick()方法中处理:

Launcher3分析及定制&主题实现_第12张图片

定制常见问题及处理

1.隐藏应用图标:
LauncherModel.Java中 loadAllapps()获取到所有应用的集合.,通过包名匹配,然后直接从集合中删除掉不需要创建桌面图标的应用.

Launcher3分析及定制&主题实现_第13张图片
2. 隐藏应用图标及应用功能.
直接在Launcher.java中通过代码实现:
让应用可见:
PackageManager.setApplicationEnabledSetting(AUX, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
隐藏应用禁止功能:
PackageManager.setApplicationEnabledSetting(AUX, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

#主题实现

Launcher3分析及定制&主题实现_第14张图片

你可能感兴趣的:(Launcher3分析及定制&主题实现)