一级桌面修改

Android的默认设计中桌面Launcher采用的是抽屉式的二级桌面样式,而在实际中大部分人都在使用的是小米式的一级桌面,我们这里使用Android6.0的源码做一个类似的修改。

首先分析一下怎么做,其它也很简单,无非就是将一级桌面workspace上没有的图标从二级桌面上挪上去,同时删除一级桌面上的“所有程序”菜单。然后要避免和解决的问题是在新的APP添加时,使图标自动添加到IDLE界面,而在长按APP图标时桌面上显示的是卸载而不是删除,同时针对某些APP首次启动会自动生成快捷方式的情况要避免图标的重复。

下面是具体的实现过程(在Android5.1上有类似的整体设计,不过并不完整)
config.xml中增加一个总的控制开关:

<bool name="config_isDisableAllApps">true</bool>

LauncherAppState.java中读取该参数:

public static boolean isDisableAllApps(){
    return sContext.getResources().getBoolean(R.bool.config_isDisableAllApps);
}

DeleteDropTarget.java中确定是否支持删除

    public static boolean supportsDrop(Object info) {
        if(LauncherAppState.isDisableAllApps()){
            if(info instanceof ShortcutInfo){
                ShortcutInfo shortcut=(ShortcutInfo)info;
                return shortcut.itemType!=LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
            }else
                return info instanceof LauncherAppWidgetInfo;
        }else{
            return (info instanceof ShortcutInfo)
                    || (info instanceof LauncherAppWidgetInfo)
                    || (info instanceof FolderInfo);
        }
    }

InfoDropTarget.java中确定是否支持查看应用信息

    @Override
    protected boolean supportsDrop(DragSource source, Object info) {
        if(LauncherAppState.isDisableAllApps()){
            if (info instanceof ShortcutInfo){
                ShortcutInfo shortcut=(ShortcutInfo)info;
                return shortcut.itemType==LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
            }else{
                return false;
            }
        }else{
            return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
        }
    }

UninstallDropTarget.java中确定是否支持卸载

    @Override
    protected boolean supportsDrop(DragSource source, Object info) {
        //zyl add 20180201
        if(LauncherAppState.isDisableAllApps()){
            if(info instanceof ShortcutInfo){
                ShortcutInfo shortcut=(ShortcutInfo)info;
                if(Utilities.isSystemApp(getContext(), shortcut.getIntent()))
                    return false;
                else
                    return shortcut.itemType==LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
            }else{
                return false;
            }
        }else{
            return supportsDrop(getContext(), info);
        }    
    }

Hotseat.java中删除中间的“所有程序”

    public boolean isAllAppsButtonRank(int rank) {
        //zyl modify 20180228
        if(LauncherAppState.isDisableAllApps())
            return false;
        else
            return rank == mAllAppsButtonRank;
    }
    void resetLayout() {
        mContent.removeAllViewsInLayout();
        //zyl add 20180228
        if(!LauncherAppState.isDisableAllApps()){
            // Add the Apps button
            Context context = getContext();

            LayoutInflater inflater = LayoutInflater.from(context);
            TextView allAppsButton = (TextView)
                    inflater.inflate(R.layout.all_apps_button, mContent, false);
            Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);

            mLauncher.resizeIconDrawable(d);
            int scaleDownPx = getResources().getDimensionPixelSize(R.dimen.all_apps_button_scale_down);
            Rect bounds = d.getBounds();
            d.setBounds(bounds.left, bounds.top + scaleDownPx / 2, bounds.right - scaleDownPx,
                    bounds.bottom - scaleDownPx / 2);
            allAppsButton.setCompoundDrawables(null, d, null, null);

            allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
            allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener());
            if (mLauncher != null) {
                mLauncher.setAllAppsButton(allAppsButton);
                allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
                allAppsButton.setOnClickListener(mLauncher);
                allAppsButton.setOnLongClickListener(mLauncher);
                allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
            }

            // Note: We do this to ensure that the hotseat is always laid out in the orientation of
            // the hotseat in order regardless of which orientation they were added
            int x = getCellXFromOrder(mAllAppsButtonRank);
            int y = getCellYFromOrder(mAllAppsButtonRank);
            CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1);
            lp.canReorder = false;
            mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
        }

InvariantDeviceProfile.java中重新选择新的workspace的xml文件并且删除针对Hotseat中图标个数的合法性检查

    //zyl add 20180228
    private boolean hasDA=LauncherAppState.isDisableAllApps();
        
    //zyl modify 20180228
    if (hs % 2 == 0&&!hasDA) {
       throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
    }

    ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
        ArrayList<InvariantDeviceProfile> predefinedDeviceProfiles = new ArrayList<>();
        // width, height, #rows, #columns, #folder rows, #folder columns,
        // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
        
        //zyl modify 20180228
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby",
                255, 300,     2, 3, 2, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_3x3));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby",
                255, 400,     3, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_3x3));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby",
                275, 420,     3, 4, 3, 4, 4, 48, 13, hasDA?4:5, 48, R.xml.default_workspace_4x4));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Stubby",
                255, 450,     3, 4, 3, 4, 4, 48, 13, hasDA?4:5, 48, R.xml.default_workspace_4x4));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus S",
                296, 491.33f, 4, 4, 4, 4, 4, 48, 13, hasDA?4:5, 48, R.xml.default_workspace_4x4));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
                359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, hasDA?4:5, 56, R.xml.default_workspace_4x4));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
                335, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, hasDA?4:5, 56, R.xml.default_workspace_4x4));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Large Phone",
                406, 694,     5, 5, 4, 4, 4, 64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
        // The tablet profile is odd in that the landscape orientation
        // also includes the nav bar on the side
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7",
                575, 904,     5, 6, 4, 5, 4, 72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
        // Larger tablet profiles always have system bars on the top & bottom
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10",
                727, 1207,    5, 6, 4, 5, 4, 76, 14.4f,  7, 76, R.xml.default_workspace_5x6));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet",
                1527, 2527,   7, 7, 6, 6, 4, 100, 20,  7, 72, R.xml.default_workspace_5x6));
        return predefinedDeviceProfiles;
    }

由于我们修改了在一级桌面上支持查看应用信息,而默认的是从二级桌面拖动到一级桌面上方的信息栏进行查看,这里因为动画的原因会造成图标卡死在信息栏上,我们需要在Workspace.java中消除有关的动画

public void onDropCompleted(final View target, final DragObject d,
            final boolean isFlingToDelete, final boolean success) {
        if (LauncherLog.DEBUG) {
            LauncherLog.d(TAG, "onDropCompleted: target = " + target + ", d = " + d
                    + ", isFlingToDelete = " + isFlingToDelete + ", mDragInfo = "
                    + mDragInfo + ", success = " + success);
        }
        //zyl add 20180228
        if(LauncherAppState.isDisableAllApps()){
            if(target instanceof InfoDropTarget){
                mDragController.cancelDrag();
                return;
            }
        }
        ...
}

如果有APP请求添加新的快捷方式,我们要排除重复的情况,修改InstallShortcutReceiver.java,添加一个判断的方法

    //zyl add 20180228
    public static boolean verifyShortcut(PendingInstallShortcutInfo pendingInfo){
        String installPackageName,installClassName; 
        try{            
            installPackageName=pendingInfo.getShortcutInfo().getIntent().getComponent().getPackageName();       
            installClassName=pendingInfo.getShortcutInfo().getIntent().getComponent().getClassName();   
        }catch(NullPointerException ex){        
            Log.i(TAG,"NullPointerException");  
            return false;           
        }                   
        String mPackageName,mClassName; 
        ShortcutInfo mShortCut;             
        Intent mIntent;             
        LauncherAppState app = LauncherAppState.getInstance();      
        synchronized (app.getModel().sBgLock) {     
            for(ItemInfo minfo:LauncherModel.sBgItemsIdMap){    
                if (minfo instanceof ShortcutInfo) {    
                    Log.i(TAG,"iteminfo="+minfo);   
                    mShortCut=(ShortcutInfo)minfo;      
                    mIntent=mShortCut.getIntent();      
                    mPackageName=mIntent.getComponent().getPackageName();   
                    mClassName=mIntent.getComponent().getClassName();           
                    if(installPackageName.equals(mPackageName)&&installClassName.equals(mClassName)){       
                        return true;                
                    }               
                }           
            }               
        }
        return false;
    }

在 static void flushInstallQueue(Context context) 方法中做判断

    //zyl add 20180228
    if(LauncherAppState.isDisableAllApps()){
        if(verifyShortcut(pendingInfo))
            return;
    }

最关键的是将Workspace上没有的APP添加上去,修改LauncherModel.java中LoaderTask部分,在加载完所有应用后进行判断,实际上我们并不是不执行加载二级桌面的操作,只是不显示

            keep_running: {
                if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
                loadAndBindWorkspace();

                if (mStopped) {
                    LauncherLog.d(TAG, "LoadTask break in the middle, this = " + this);
                    break keep_running;
                }

                waitForIdle();

                // second step
                if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
                loadAndBindAllApps();
                
                //zyl add 20180228
                if(LauncherAppState.isDisableAllApps()){
                    verifyApplications();
                }
            }

添加新的方法verifyApplications()

        //zyl add 20180228
        private void verifyApplications() {
                final Context context = mApp.getContext();

                // Cross reference all the applications in our apps list with items in the workspace
                ArrayList<ItemInfo> tmpInfos;
                ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();
                synchronized (sBgLock) {
                    for (AppInfo app : mBgAllAppsList.data) {
                        tmpInfos = getItemInfoForComponentName(app.componentName, app.user);
                        if (tmpInfos.isEmpty()) {
                            // We are missing an application icon, so add this to the workspace
                            added.add(app);
                            // This is a rare event, so lets log it
                            Log.e(TAG, "Missing Application on load: " + app);
                        }
                    }
                }
                if (!added.isEmpty()) {
                    addAndBindAddedWorkspaceItems(context, added);
                }
        }

另外既然只有一级桌面,那当一个APP被卸载后,我们一般希望图标会自动排列,而不是空出来,我们添加一个算法来修改数据库

    //zyl add 20180228
    private void changeItemFromDatabase(Context context,final ArrayList<ItemInfo> items){
        int cellX=0, cellY=0;
        int screenId;   
        for (ItemInfo item : items){
            screenId=(int)item.screenId;  
            LauncherAppState app = LauncherAppState.getInstance();
            InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
            final int xCount = (int) profile.numColumns;
            ArrayList<ItemInfo> changeditems =new ArrayList<ItemInfo>();       
            for (ItemInfo i : sBgWorkspaceItems){
                if (i.container == LauncherSettings.Favorites.CONTAINER_DESKTOP){   
                    if(screenId == i.screenId && i.cellY>=item.cellY ){  
                        if(i.cellY==item.cellY && i.cellX>item.cellX){
                            cellX = i.cellX-1;
                            cellY = i.cellY;
                        }else if(i.cellY>item.cellY){
                                if(i.cellX==0){
                                    cellX = xCount-1;
                                    cellY = i.cellY-1;
                                }else{
                                    cellX = i.cellX -1;
                                    cellY = i.cellY;
                                }
                        }else{
                            cellX = i.cellX;
                            cellY = i.cellY;
                        }
                        i.cellX = cellX; 
                        i.cellY = cellY;
                        changeditems.add(i);    
                    }
                }
            }
            moveItemsInDatabase(context, changeditems, item.container, screenId);  
        }       
    }

还是LauncherModel.java,PackageUpdatedTask中做修改

          if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
                for (String pn : removedPackages) {
                    //zyl add 20180228
                    if(LauncherAppState.isDisableAllApps()){
                        changeItemFromDatabase(context,getItemsByPackageName(pn,mUser));
                    }
                    deletePackageFromDatabase(context, pn, mUser);
                }
                ...

此外,我们顺便将workspace上边距减小(删除QSB后Idle上方留白过多),修改DeviceProfile.java的getWorkspacePadding方法

            ...
            } else {
                // Pad the top and bottom of the workspace with search/hotseat bar sizes
                padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
                        2*edgeMarginPx,//zyl modify 20180228    
                        desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
                        paddingBottom);
            }
            ...

同时调整参数文件dimens.xml

    <dimen name="dynamic_grid_search_bar_height">25dp</dimen> <!--zyl modify 20180228-->
    <!-- We want 46dp extra for the tall search bar. -->
    <dimen name="dynamic_grid_search_bar_height_tall">94dp</dimen>
    <dimen name="qsb_internal_padding_top">0dp</dimen>  <!--zyl modify 20180228-->
    <dimen name="qsb_internal_padding_bottom">0dp</dimen>   <!--zyl modify 20180228-->

这样我们的一级桌面就成形了,不会有其它什么问题。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,098评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 我今天把自己做业务和人接触的一些心得分享一下。 第一是价值观,先了解一下对方是不是和自己价值观一样,比如我和你都是...
    杨荣瓒阅读 142评论 0 2
  • 你会因为一首歌而爱上生活 你会因为一句话而选择痛苦 你会因为一条美丽的公路而爱上旅行 你会因为忧伤的季节而在黄昏沉...
    皆非_lx阅读 227评论 0 1
  • 1小时候的时光大都已经模糊,尽管我这样自许记事早的人。 记不清多久没有聊聊小时候了,大抵是小时候的人生不是我们自己...
    夏尔_b997阅读 265评论 0 1