Android Launcher3的自定义修改总结

Android Launcher3的自定义修改总结

       最近尝试看看Android源码中的Launcher3的代码并试着进行了一些自定义的修改,现在对自己尝试修改的过程做个总结并回顾一下关于Launcher3代码的所认识到的东西。

       Launcher其实就是Android系统中的桌面,其实也是一个apk,通过打包后安装到系统应用中的,属于整个Android系统中的Framework层。此次阅读并尝试修改的Launcher版本是Launcher3,整个项目可以从github上clone到,我修改的Launcher3是从朋友那里直接拿过来进行运行的,就是google提供的原生代码。

       Launcher3是自己尝试分析和修改的第一个Framework模块代码,所以,先说一下拿到项目后开始着手的分析步骤和着手处。首先,Launcher3是一个独立项目,可以编译成独立的apk运行在android手机上,所以打开项目,大致浏览了目录结构后,对整体的项目,以及代码中类的数量等做一个大致的浏览,心中可以大致关于项目有个概念;然后接下来就是先运行一下项目,编译到设备上看一下效果。 看到效果之后,就去找整个项目的AndroidMainFest.xml文件,在文件中找程序的入口类,代码就进入java类了,开始进入分析了。在Android,组件都是有生命周期的,所以,在分析java代码时,先根据生命周期的调用顺序,从前向后开始分析。

 1.Launcher入口:Launcher类作为整个启动器的应用入口,在其onCreate方法中完成:LauncherAppSate类的初始化,LauncherAppState使用了单例模式;通过LauncherAppState实例化对象获取运行设备的DeviceProfile对象,主要就是设备默认的一些信息;随后会实例化或获取一些边量;setContentView()方法之后调用setupViews()方法完成对launcher.xml文件的inflate以及控件的设置;接着注册内容观察者对象和广播接收者,注册的该观察者对象为AppWidgetResetObserver,广播接收者为的action为ACTION_CLOSE_SYSTEM_DIALOGS,当每次按下home键时,都会触发action为ACTION_CLOSE_SYSTEM_DIALOGS的广播;接下来就是设置Launcher桌面的监听回调;最后如果是首次进入launcher,会显示使用介绍界面,非首次使用,不会显示使用介绍。

2.launcher.xml布局文件中的放置的控件分析。在Launcher中,把手机屏幕分为了几个主要的部分,屏幕上部的搜索框,workspace,indicator,hotseat,除此之外,还有正常情况下隐藏的overview_panel,focus_indicator,apps_customize_pane等控件。通过上面的介绍然后依次去查看.xml文件就能将控件弄明白,最常见的大图标,小图标,系统widget等都是放在worksapce中,有一个用来表示应用页数和当前页的页码指示器就是indicator,再屏幕的最下面有一横排快捷方式,一般默认为电话,短信息,浏览器等图标,该底部控件就是存在于hotseat。其他正常情况下隐藏的就对应着长按屏幕空白时会出现的上下两个控件。需要注意一下的是,为了简化launcher.xml文件结构,使其简单清晰,使用了<include>标签,用于包含其他的布局文件。该标签能方便的捋清页面结构。

3.Workspace中放置的对象。再android设备屏幕上,最最常见的就是能够放置各种安装的应用的图标,系统应用图标入设置,图库时钟等,多个图标放在一起的文件夹Folder以及用户添加的小控件,比如快捷开关长条等小控件。在分析源码的时候,查看到一个Bean类叫ItemInfo.java,该类封装定义了显示在屏幕上的单个图标的基本信息,包含cellx,celly,spanx,spany等此类和该图标位置有关的变量,也包含title,description等描述信息,此外,也有表示该图标的类型的变量type,注释中描述type有ITEM_TYPE_APPLICATION,ITEM_TYPE_SHORTCUT,ITEM_TYPE_FOLDER,ITEM_TYPE_APPWIDGET四种类型,四种类型都在LauncherSettings.Favorites中定义的。这些对象最终都是绑定在一个叫CellLayout控件里面的,从命名中就可以看到CellLayout就是一个格子控件,该控件可以将屏幕划分成4*4或者5*5或者其他等等类似的网格的布局,从而按照不同的设置根据用户需求和意愿将要显示的图标放置在cellLayout中的相应的位置上。所以,其实是将要显示的图标添加到cellLayout当中对应的位置,而CellLayout又存在于workspace中,workspace中包含多个cellLayout,每一页的屏幕中央显示的位置都是一个cellLayout在worksapce中。

4.HotSeat中隐藏显示所有app按钮,控制HotSeat控件的个数由横排5个变成4个。查看launcher.xml中包含的hotseat布局发现。根布局是Hotseat控件,其中包含了一个cellLayout控件。所以,hotseat横排5个图标是填充到cellLayout布局中,进而进行显示的。首先解决本条中的第一个问题,将hotseat中用于点击弹出所有app图标的按钮进行隐藏,之所以这么做是因为我们看到在很多的国产手机厂商定制的系统中就有很多是将所有的应用图标都显示到了worspace中,而隐藏来hotseat中的点击显示所有图标的按钮,例如连线,小米,很多很多。所以就想来尝试一下。还是从最基本的思路出发,从控件出发,一步一步找该控件是如何将默认的图标以及展示所有图标的按钮加载出来的,找到加载的地方,进行自定义修改就好了。分析如下:我们在布局文件中看到,hotseat中有唯一的一个控件cellLayout,所以是将图标添加到cellLayout中去,下一步就是去HotSeat中去找如何向cellLayout中添加控件的就好了。脚步来到HotSeat中,HotSeat就是继承自FrameLayout的一个帧布局,先看构造方法,三个构造方法根据参数不同依次调用,最后在三个构造方法中进行一些变量的获取和设置操作。继续向下看方法,发现有一个方法叫onFinishInflate ()方法,一看就知道,Hotseat控件在inflate完成后会调用该方法,在该方法的最后调用了一个名字为resetLayout()的方法。继续跟进,首先,cellLayout.removeAllViewsInLayout(), 将CellLayout中的控件全部移除。下面,进行了一个判断,然后看到了一个叫allAppsButton的TextView,从命名来看就是所有应用按钮,其实就是那个需要隐藏的按钮,原来是一个TextView,在if条件代码块的最后,cellLayout.addValueToCellLayout();也就是将allAppsButton添加进到了CellLayout;这样就明白来,如果想让显示所有app的按钮隐藏,只要不执行if语句内代码块就好了,判断条件为!LauncherAppState.isDisableAllApps(),根据方法名意思就是是否隐藏所有应用,继续根据代码查看,返回boolean值,我们直接将该方法的返回值修改为true,隐藏显示所有应用按钮的需求就完成了。继续进行第二个问题,之前将显示所有应用的图标进行了隐藏,但是存在一个问题就是横排还是5个图标的位置,大部分的国产定制系统都是显示4个,所以猜测一定是修改hotseat中celllayout控件的孩子个数来控制hotseat横排图标的个数,开始找找看。既然是hotseat中的图标的个数,应该还在hotseat这个类中,上面分析隐藏代码的时候分析到了onFinishInlfate方法,在该方法的最后添加了allAppsButton,我们继续在该方法中进行寻找线索。代码就在onFinishInflate方法中,首先实例化了LauncherAppState对象,然后获取到 了DeviceProfile方法,下面得到cellLayout,接着进行了条件判断,无论哪种情况,都是只有一句代码:cellLayout.setGridSize()方法。这就是设置cellLayout的大小啊,根进代码进去查看,setGridSize()方法刚好有两个参数,根据代码中的变量赋值语句,就是x轴上子控件的个数和y轴上的子控件的个数。所以我们就明白了,我们回到hotseat中,直接将两个参数的值修改为4,1表示横轴4个孩子,纵轴一个。然后运行程序,果然符合自己的需求。回顾一下,第二个程序修改,其实并没有修改的很好,原来的setGridSize()方法是赋值的变量值,在launcher中,刚高hotseat只进行了一处setGriadSize()方法,如果多个地方调用,很可能就会出现bug。所以我们应该找到最终的代码定义的地方进行修改,查看代码,参数的来源是DeviceProfile类,代码跟入查看,最后找到赋值的位置在DynamicGrid类中将对应Nexus 5的对象处的5修改成4,即可达到想要的效果.

5.其实我们修改了hotseat中的横向子控件个数后,我们还可以根据自己的需求或者兴趣修改worksapace中的celllayout的行和列的数据,其修改原理和hotseat中一样。

6.在修改了隐藏所有空间方法的返回值为true时,运行Launcher就会发现所有的图标都会被加载到workspace中,点击显示所有应用图标的按钮已经被隐藏。当我们按住一个图标时,可以随时拖动,可以进行删除,屏幕上方会出现删除按钮,系统图标职能拖动不能删除。但是我们看很多的国产定制系统桌面会发现,在桌面上拖动第三方应用是可以删除的,系统应用时可以查看应用信息的。所以,下一步的目标就是长按图标进行拖动时,能够根据图标的不同类型进行动态的显示卸载活着应用信息等控件。在删除时需要找到DeleteDropTarget类,其中的两个方法需要我们去分析,一个时onDragStart();另一个是completeDrop()方法。在onDragStart()方法中,有两个变量会引起我们的注意,这两个变量都是boolean值,分别是useUninstallLabel,useUninstallLabel,就是分别对应卸载和删除的控件标签是否显示的变量。通过尝试可以知道,其实就是通过改变这两个boolean值来进行显示对应的标签的。接下来的任务就是负责将这个量boolean值赋上合理的值。要想正确赋值,需要考虑几种情况,因为每种情况需要显示的标签不一致,通过分析,移动图标时显示的内容一共有三类,第一类是添加到worksapce中的系统组件,比如闹钟,快捷开关,日历等系统组件,当用户拖动此类组件时,我们需要在屏幕顶部左侧显示删除按钮,右侧显示应用信息按钮;第二类是系统应用,比如设置,图库,相机等,当用户拖动此类图标时,需要在屏幕上部只显示应用信息按钮,不能删除,也不能卸载;第三类是用户下载安装的第三方的应用,当用户拖动此类图标时,我们需要在屏幕上方左侧显示卸载,右侧显示应用信息按钮;以上三种情况就是我们的使用场景和需求。在DeleteDropTarget的onDragStart()方法中,依次分析三种情况,完成需求的修改。其中,需要说明一下,在onDragStart方法的参数中,有一个Object类型的info变量,在分析三种情况时,需要对info进行类型判断,三种情况其实就是两种类型,一种时AppWidgetInfo,一种是ShortCut类型,应用程序和第三方应用程序都属于shortcut类型,仅仅是通过一个flags值来区分是下载应用还是系统应用。需要着重看该方法和修改该方法来完成本条的需求。第二部就是卸载应用标签出现时,要触发相应的卸载动作;在DeleteDropTarget中有一个completeDrop()方法,该方法就是在完成拖拽动作后执行的方法,查看该方法,只需要满足判断条件,就会触发删除动作,所以,我们通过修改判断条件,使if判断成立,程序就会进入卸载程序块,开启卸载动作。

7.查看组件的详细信息。在适应了6条的需求后,在屏幕上拖动组件或者图标可以删除,也可以查看应用信息;但是有一个问题是,拖拽图标到查看应用程序信息标签时,打开了应用信息的界面,当按返回键返回主界面时,会发现原来的图标不见了,这不是我们想要的。通过测试后还发现,图标其实并没有删除,只是不可见了而已,如果我们拖拽一个其他图标到之前消失图标的位置,系统其实会显示是一个文件夹,然后我们再打开文件夹,又看到了里面的所有图标。到这里也就明白了,其实是拖拽的时候把图标所在位置的图标隐藏了,当我们完成拖拽功能时,如果是卸载,会自动更新删掉,如果时删除也会根据删除动作自动更新删除,但是查看应用信息并不应该更新删除,也不应该隐藏。类似于DeleteDropTarget,猜想应该也会存在一个AppInfoDrag类似的类,进行全局文件搜索,果然发现一个InfoDropTarget类,该类和DeleteDropTarget是一样的;分析里面的代码;在该类的acceptDrop()方法中,我们发现对dragInfo进行类类型判断,下面有一个startApplicationDetailsActivity方法,判断应该就是这个方法是弹出应用信息界面的动作,将该方法注释掉,运行程序,果然不会触发打开应用程序界面。根据之前的分析,我们需要在打开应用程序信息动作之后,将拖拽图标设置回可见,就可以达到显示图标的目的了。首先应该先看一下drapinfo本身有没有什么属性可以设置其可见性的,通过查找,找到一个cancelled,将cancelled设置为true,运行程序,果然成功。但是在查看系统组件的时候,系统组件这个控件还是会消失不可见,按照第6条时的分析情况,应该是系统组件这类情况没有进行判断,于是回到acceptDrop方法中,添加对系统组件的类型判断,然后进行类型转换,尝试运行程序,达到效果

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页