需求:

1、 用android系统launcher 隐藏主菜单 所有应用显示在桌面 即workspace上;

2、隐藏launcher上方默认的google search;

3、切换一套launcher主题。

实现效果:

分析:

1、 隐藏主菜单 ,google默认在android L 版本有一个隐藏主菜单的开关——LauncherAppState.isDisableAllApps()

返回 true 隐藏,返回 false 显示。

2、隐藏google search ,有好多方法。比较简单 ,本文将一笔带过

3、切换主题 上次有提过实现思路,具体看安装包性能优化,动态加载资源

下面是填坑之路

1、隐藏主菜单

首先设置 LauncherAppState.isDisableAllApps() 隐藏主菜单

具体原理的话



这个将会在Hotseat.java中根据上面条件进行判断是显示还是隐藏 ,Allapp其实就是一个TextView 当然仅仅这样是不够的 更细节的东西有时间的话在深入分析

坑一、通过上面的步骤的话 我们默认是把所有应用显示在了workspace上,然而用系统launcher的人都知道在workspace上默认只有移除动作的如下

只有在主菜单中拖拽才有 应用信息和卸载操作,这个问题将直接导致,如果你想卸载应用只能到设置里面去卸载,在桌面上移除只是remove掉了 而它依然还存在 重启launcher就会发现这个应用又回来了,这就是个比较坑爹的事了,

解决办法:

首先找到顶部显示 uninstall和Appinfo的地方

通过分析最后发现是在ButtonDropTarget两个子类里面显示的

DeleteDropTarget和InfoDropTarget 看名字也知道他们是干什么的了,而ButtonDropTarget又实现了launcher定义的两个接口

public class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener

发现google工程师就是比较牛逼起名字都起的这么好。

DropTarget 监听目标的放置操作

DragController 拖拽事件的控制类

而我们会发现这两个类里面都有一个isVisible 通过分析发现这个就是控制launcher顶部的两个标签是否显示的开关。

在InfoDropTarget里面 我们发现

 if (!source.supportsAppInfoDropTarget()) {
            isVisible = false;
        }

而supportsAppInfoDropTarget 是一个接口的方法,它有三个实现类



只有是AppsCustomizePagedView时才返回true

另外两个都是false 所以我们知道了为什么在主菜单里能显示应用信息而桌面不能显示应用信息的原因了

所以这里把workspace的这个方法也修改为true

@Override
    public void onDragStart(DragSource source, Object info, int dragAction) {
        if (LauncherLog.DEBUG) {
            LauncherLog.d(TAG, "onDratStart: source = " + source + ", info = " + info
                    + ", dragAction = " + dragAction);
        }

        boolean isVisible = true;

        // Hide this button unless we are dragging something from AllApps
        //by lly for disableAllapp 20161112 start
         if(info instanceof FolderInfo){
            isVisible = false;
        }
        if(info instanceof LauncherAppWidgetInfo){
            isVisible = false;
        }
         if(info instanceof PendingAddWidgetInfo){
            isVisible = false;
        }
        //by lly for disableAllapp 20161112 end
        if (!source.supportsAppInfoDropTarget()) {
            isVisible = false;
        }
        ....
        }

然后在各个情况判断下 当是文件 或者桌面小部件或者从widgets视图中拖拽时都让它不显示appinfo

至此 InfoDropTarget 处理 就完成了

下面看下DeleteDropTarget的处理

其实和处理InfoDropTarget 类似,只是这里更繁琐一点 下面就直接上代码了

 @Override
    public void onDragStart(DragSource source, Object info, int dragAction) {
        boolean isVisible = true;
        //by lly for disableAllapp
        boolean useUninstallLabel =  isShortcut(source,info);//isAllAppsApplication(source, info);
        boolean useDeleteLabel = !useUninstallLabel && source.supportsDeleteDropTarget();

        // If we are dragging an application from AppsCustomize, only show the control if we can
        // delete the app (it was downloaded), and rename the string to "uninstall" in such a case.
        // Hide the delete target if it is a widget from AppsCustomize.
        //by lly for disableAllapp start
         if(info instanceof ShortcutInfo){
            try{
                ShortcutInfo appInfo = (ShortcutInfo) info;
                PackageManager packageManager = getContext().getPackageManager();
                ApplicationInfo ai = packageManager.getApplicationInfo(appInfo.intent.getComponent().getPackageName(), 0);
                        mIsSysApp = (ai.flags & ApplicationInfo.FLAG_SYSTEM)>0;
            } catch (NameNotFoundException e) {
            e.printStackTrace();
            }
            }
            //by lly for disableAllapp end
        if (!willAcceptDrop(info) || isAllAppsWidget(source, info)) {
            isVisible = false;
        }

  //by lly for disallapp 20161112 start
    private boolean isShortcut(DragSource source, Object info) {
        return source.supportsAppInfoDropTarget() && (info instanceof ShortcutInfo);
    }
    //by lly for disallapp 20161112 start

private boolean isAllAppsApplication(DragSource source, Object info) {
        return source.supportsAppInfoDropTarget() && (info instanceof AppInfo);
    }
 public static boolean willAcceptDrop(Object info) {
        if (info instanceof ItemInfo) {
            ItemInfo item = (ItemInfo) info;

            ...
            if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
                item instanceof ShortcutInfo) {
                if (LauncherAppState.isDisableAllApps()) {
                    ShortcutInfo shortcutInfo = (ShortcutInfo) info;
                    //by lly for disableAllapp start
                    if(!mIsSysApp){
                        shortcutInfo.flags = 1;
                    }
                    //by lly for disableAllapp end
                    return (shortcutInfo.flags & AppInfo.DOWNLOADED_FLAG) != 0;
                } else {
                    return true;
                }
            }
        }
        return false;
    }

看上面有注释的地方差不多就知道我是怎么做的了,首先我是让上面都显示uninstall

主要就是useUninstallLabel 为true

接着判读是否是系统应用 因为系统应用是不能卸载的

if(info instanceof ShortcutInfo){
            try{
                ShortcutInfo appInfo = (ShortcutInfo) info;
                PackageManager packageManager = getContext().getPackageManager();
                ApplicationInfo ai = packageManager.getApplicationInfo(appInfo.intent.getComponent().getPackageName(), 0);
                        mIsSysApp = (ai.flags & ApplicationInfo.FLAG_SYSTEM)>0;
            } catch (NameNotFoundException e) {
            e.printStackTrace();
            }
            }

根据是否是系统应用来确定 flags

从而控制isVisible的值

至此 显示uninstall已经出来完成

接下来看功能即 拖拽到uninstall标签怎么删除

 private void completeDrop(DragObject d) {
        ...
        if (LauncherLog.DEBUG) {
            LauncherLog.d(TAG, "completeDrop: item = " + item + ", d = " + d);
        }
        if (isAllAppsApplication(d.dragSource, item)) {
          ...
        } else if (isUninstallFromDisableAllApp(d)) {//by lly for
            ...

                mWaitingForUninstall = mLauncher.startApplicationUninstallActivity(
                        componentName, shortcut.flags, user);
        }
     }

 private boolean isUninstallFromWorkspace(DragObject d) {
        if (LauncherAppState.isDisableAllApps() && isWorkspaceOrFolderApplication(d)) {
            ShortcutInfo shortcut = (ShortcutInfo) d.dragInfo;
            // Only allow manifest shortcuts to initiate an un-install.
            return !InstallShortcutReceiver.isValidShortcutLaunchIntent(shortcut.intent);
        }
        return false;
    }
    //by lly for disableAllapp start
      private boolean isUninstallFromDisableAllApp(DragObject d) {
        if (d.dragInfo instanceof LauncherAppWidgetInfo) {

            return false;
        }
        return true;
    }
    //by lly for disableAllapp end

依然是重写判读条件 没什么好说的

到这一步基本功能 就已经实现 但是操作的话发现拖拽到标签上松手 图标消失了 不管是appinfo标签还是uninstall标签

这里直接给出答案 他不是消失之时被隐藏了你拖拽个别的图标那个位置他就又出现了 但这确实是个bug 怎么解呢

/** Indicates that the drag operation was cancelled */
    public boolean cancelled = false;

 if (componentName != null) {
            mLauncher.startApplicationDetailsActivity(componentName, user);
        }
        d.cancelled = true;//by lly

当显示应用信息的时候直接让cancelled 为true表示取消这个拖拽事件就OK了

在DeleteDropTarget中 把animateToTrashAndCompleteDrop(d)提到acceptDrop里来操作

 @Override
    public boolean acceptDrop(DragObject d) {
        //by lly for disableAllapp start
            animateToTrashAndCompleteDrop(d);
            if(isUninstallFromDisableAllApp(d)){
                d.cancelled = true;
            }
        return false;//willAcceptDrop(d.dragInfo);
      //by lly for disableAllapp end
    }

到这里坑一就填平了,测试了一下暂时没有发现这样修改有新坑出现。

坑二

通过google提供的方法隐藏主菜单后 1、按菜单键桌面小部件界面出现不了,2、 当长按桌面空白处进入小部件界面然后返回 界面显示异常,3、拖拽小部件到桌面松开手后显示异常。

这个就不买关子了直接说明原因,至于我为什么知道你没看这都星期几了 我还在解bug么

因为按google这样设置后可以看到

void resetLayout() {
        mContent.removeAllViewsInLayout();

        if (!LauncherAppState.isDisableAllApps()) {
            ...
            if (mLauncher != null) {
                allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
                mLauncher.setAllAppsButton(allAppsButton);
                allAppsButton.setOnClickListener(mLauncher);
                allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
            }

           ...
        }
    }

这个地方主要就是那个allapp菜单添加的地方但是那个对我们分析来说没什么用 主要是看

 mLauncher.setAllAppsButton(allAppsButton);

这里把这个菜单设置给了launcher


    /**
     * Sets the all apps button. This method is called from {@link Hotseat}.
     */
    public void setAllAppsButton(View allAppsButton) {
        mAllAppsButton = allAppsButton;
    }

    public View getAllAppsButton() {
        return mAllAppsButton;
    }

然后通过getAllAppsButton得到这个mAllAppsButton最后在showAppsCustomizeHelper和hideAppsCustomizeHelper里面用到了这个mAllAppsButton其实是个TextView 然而 我们设置隐藏主菜单后 这个mAllAppsButton是空的所以导致了这个问题,那么知道了原因解决就很好办了 。

 // If for some reason our views aren't initialized, don't animate
       // boolean initialized = getAllAppsButton() != null;

        if (animated /*&& initialized*/) {
        ...
        }

直接不要他了不就可以。 当然下面几个地方也要一并去掉。

至此坑二也填平了

2、隐藏launcher上方默认的google search;

3、切换一套launcher主题。

这两个需求比较简单就不再分析了 如有需要请私信给我。

android launcher 之踩到的坑的更多相关文章

  1. android开发过程中踩过的坑

    1) 4.X下 viewgroup 不一定会向下传递requestLayout,当onlayout的速度比较慢(比如子View比较复杂之类的原因),系统会跳帧!此时子View下层的view可能就不会再 ...

  2. Android Studio安装踩坑

    title: Android Studio安装踩坑 date: 2018-09-07 19:31:32 updated: tags: [Android,Android Studio,坑] descri ...

  3. 【转载】Fragment 全解析(1):那些年踩过的坑

    http://www.jianshu.com/p/d9143a92ad94 Fragment系列文章:1.Fragment全解析系列(一):那些年踩过的坑2.Fragment全解析系列(二):正确的使 ...

  4. 在Mac osx使用ADT Bundle踩过的坑

    前言 本篇博客整理一下笔者在Mac下使用ADT Bundle踩过的坑,Google现在也不支持Eclipse了,开发者也到了抛弃Eclipse的时候,但考虑到大部分Java的开发者还是比较习惯与Ecl ...

  5. 小程序——微信小程序初学踩过的坑

    微信小程序初学踩过的坑 一.前言     最近因为某些需要和个人兴趣打算开发一下微信小程序,经过在官方网站上的基本了解,我大体知道了微信小程序开发的大致过程,其实最本质的就是MVVM,借用了很多模式上 ...

  6. Dcloud开发webApp踩过的坑

    Dcloud开发webApp踩过的坑 一.总结 一句话总结:HTML5+扩展了JavaScript对象plus,使得js可以调用各种浏览器无法实现或实现不佳的系统能力,设备能力如摄像头.陀螺仪.文件系 ...

  7. Android使用WebView开发常见的坑

    原文链接:http://mp.weixin.qq.com/s?__biz=MzAwODE1NTI2MQ==&tempkey=uP3a%2BOgIN7vPbLfJp3BTCl2KabYi1%2F ...

  8. apicloud地图、即时通讯、人脸识别登录、以及平时踩过得坑

    apicloud技术浅谈 导语 apicloud 的学习也有一段时间了,这是我个人的一些经验,和踩过的坑,希望对大家能有一些帮助. apicloud的知识准备 apicloud 是一个用原生的思想搭建 ...

  9. 转:Flutter开发中踩过的坑

    记录一下入手Flutter后实际开发中踩过的一些坑,这些坑希望后来者踩的越少越好.本文章默认读者已经掌握Flutter初步开发基础. 坑1问题:在debug模式下,App启动第一个页面会很慢,甚至是黑 ...

随机推荐

  1. 使用Vertx重构系统小结

    背景 前几个月,使用Vertx重构了公司的一个子系统,该系统负责公司核心数据subscriber的采集.处理.存储和搜索.这里介绍下重构该系统时的一些关键点. 架构 重构前系统部署图: 重构前系统主要 ...

  2. [LeetCode] Open the Lock 开锁

    You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', '3', ...

  3. [LeetCode] Dota2 Senate 刀塔二参议院

    In the world of Dota2, there are two parties: the Radiant and the Dire. The Dota2 senate consists of ...

  4. [SCOI2012]滑雪与时间胶囊

    题目描述 a180285非常喜欢滑雪.他来到一座雪山,这里分布着MMM条供滑行的轨道和NNN个轨道之间的交点(同时也是景点),而且每个景点都有一编号iii(1≤i≤N1 \le i \le N1≤i≤ ...

  5. [BZOJ]1069: [SCOI2007]最大土地面积

    题目大意:给出二维平面上n个点,求最大的由这些点组成的四边形面积.(n<=2000) 思路:求出凸包后旋转卡壳枚举对踵点对作为四边形的对角线,枚举或二分另外两个点,复杂度O(n^2)或O(nlo ...

  6. bzoj 2594: [Wc2006]水管局长数据加强版

    Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一 ...

  7. bzoj4596[Shoi2016]黑暗前的幻想乡 Matrix定理+容斥原理

    4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 464  Solved: 264[Submit][Sta ...

  8. Android Studio创建/打开项目时一直处于Building“project name”Gradle project info的解决办法

    重新安装了Android studio 之后, 启动android studio,打开原来的项目,界面一直停留在: 一直停留在此界面的原因是:Android studio 在下载 Gradle ,但是 ...

  9. JS中三种字符串连接方式及其性能比较

    工作中经常会碰到要把2个或多个字符串连接成一个字符串的问题,在JS中处理这类问题一般有三种方法,这里将它们一一列出顺便也对它们的性能做个具体的比较. 第一种方法  用连接符“+”把要连接的字符串连起来 ...

  10. Java连接FTP成功,但是上传是失败,报错:Connected time out

    Java代码在本机上传文件到FTP服务器的时候成功,但是部署到测试服务器的时候出现,连接FTP成功但是上传失败,并且报Connected time out错误: 测试服务器和FTP服务都在阿里云上:( ...