当前位置: 移动技术网 > 移动技术>移动开发>Android > android 9.0 Launcher3 去掉抽屉式,显示所有 app

android 9.0 Launcher3 去掉抽屉式,显示所有 app

2019年11月08日  | 移动技术网移动技术  | 我要评论

效果图

在这里插入图片描述

修改思路

1、增加全局控制变量 sys.launcher3.is_full_app,用来动态切换

2、增加两套布局,对应有抽屉和无抽屉

3、去除 allappsbutton

4、将 allappscontainerview 中的图标加载到 workspace

5、新安装的 app 自动添加图标到 workspace

6、替换 workspace 图标长按删除选项为取消

7、屏蔽上拉显示抽屉页面手势

8、修改页面指示线为圆点

上代码

1、增加全局控制变量 sys.launcher3.is_full_app

1) 在 launcherappstate 中增加静态方法 isdisableallapps(), 通过修改 settings 中自定义的值 sys.launcher3.is_full_app

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\launcherappstate.java

   private static  context mcontext;

public static boolean isdisableallapps() {
        if (mcontext != null) {
            return settings.system.getint(mcontext.getcontentresolver(), 
                "sys.launcher3.is_full_app", 0) == 1;
        }
        return true;
    }

vendor\mediatek\proprietary\packages\apps\launcher3\androidmanifest-common.xml

2) androidmanifest-common.xml 中增加权限

<uses-permission android:name="android.permission.write_settings" />

3) 在 settingsactivity 中增加 switchpreference 用以动态修改 sys.launcher3.is_full_app

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\settingsactivity.java

在内部类 launchersettingsfragment 中重写 onpreferencetreeclick() 用以监听 switchpreference 点击

/**
     * this fragment shows the launcher preferences.
     */
    public static class launchersettingsfragment extends preferencefragment {
    
    .....
    
    @override
    public void oncreate(bundle savedinstancestate) {
            super.oncreate(savedinstancestate);

    ....

            //读取保存的值,初始化 switchpreference 的初始状态,是否选中
            int isfull = settings.system.getint(getactivity().getcontentresolver(), 
                "sys.launcher3.is_full_app", 0);
            log.d("launcher3", "sys.launcher3.is_full_app="+isfull);
            switchpreference fullswitch = (switchpreference) findpreference("pref_is_full_app");
            fullswitch.setchecked(isfull==1);
     }


    
    //add for change is_full_app value
    @override
    public boolean onpreferencetreeclick(preferencescreen preferencescreen, preference preference) {
            boolean result = true;
            final string key = preference.getkey();

             if ("pref_is_full_app".equals(key)) {
                boolean checked = ((switchpreference) preference).ischecked();

                settings.system.putint(getactivity().getcontentresolver(), "sys.launcher3.is_full_app",
                        checked ? 1 : 0);

                log.e("launcher3", "switchpreference checked="+checked);

                // value has changed
                progressdialog.show(getactivity(),
                        null /* title */,
                        getactivity().getstring(r.string.full_app_override_progress),
                        true /* indeterminate */,
                        false /* cancelable */);
                new looperexecutor(launchermodel.getworkerlooper()).execute(
                        new overrideapplyhandler(getactivity()));
                
            }
            return result;
        }

}

点击 switchpreference 后需要保存 sys.launcher3.is_full_app 新值,同时清除 launcher3 的缓存,延时启动并结束当前进程

清除缓存方法 clearapplicationuserdata 在 launcher3 中编译报错,所以通过发送广播到 setting 中进行真正的清缓存操作

    //add for change is_full_app value
    private static class overrideapplyhandler implements runnable {

        private final context mcontext;

        private overrideapplyhandler(context context) {
            mcontext = context;
        }

        @override
        public void run() {
            // clear the icon cache.
            launcherappstate.getinstance(mcontext).geticoncache().clear();

            // wait for it
            try {
                thread.sleep(1000);
            } catch (exception e) {
                log.e("launcher3", "error waiting", e);
            }

            // schedule an alarm before we kill ourself.
            intent homeintent = new intent(intent.action_main)
                    .addcategory(intent.category_home)
                    .setpackage(mcontext.getpackagename())
                    .addflags(intent.flag_activity_new_task);
            pendingintent pi = pendingintent.getactivity(mcontext, 42,
                    homeintent, pendingintent.flag_cancel_current | pendingintent.flag_one_shot);
            mcontext.getsystemservice(alarmmanager.class).setexact(
                    alarmmanager.elapsed_realtime, systemclock.elapsedrealtime() + 50, pi);

            //clear data will kill process
            intent intent = new intent("com.android.action.clear_app_data");
            intent.putextra("pkgname", "com.android.launcher3");
            intent.addflags(0x01000000);
            mcontext.sendbroadcast(intent);
            log.i("launcher3", "clearing user data com.android.launcher3");

            // kill process
            android.os.process.killprocess(android.os.process.mypid());
        }
    }

4) settingsactivity 对应的 xml 文件修改 launcher_preferences

vendor\mediatek\proprietary\packages\apps\launcher3\res\xml\launcher_preferences.xml

 <switchpreference
        android:key="pref_is_full_app"
        android:title="@string/is_full_app_title"
        android:summary="@string/is_full_app_desc"
        android:defaultvalue="false"
        android:persistent="true" />

对应的 string 文件就不贴了,自己增加下就行

2、增加两套布局,对应有抽屉和无抽屉

加载布局文件对应的 xml 为 vendor\mediatek\proprietary\packages\apps\launcher3\res\xml\device_profiles.xml

launcher3 通过获取 minwidthdps 和 minheightdps 来确定加载哪一个 profile,我的平板分辨率是 1280*800 的,增加两个 profile 节点

 <profile
        launcher:name="tablet"
        launcher:minwidthdps="376"
        launcher:minheightdps="586"
        launcher:numrows="4"
        launcher:numcolumns="5"
        launcher:numfolderrows="4"
        launcher:numfoldercolumns="5"
        launcher:iconsize="50"
        launcher:icontextsize="11"
        launcher:numhotseaticons="5"
        launcher:defaultlayoutid="@xml/default_workspace_tb_5x6"
        />

    <profile
        launcher:name="tablet_no_all_app"
        launcher:minwidthdps="380"
        launcher:minheightdps="590"
        launcher:numrows="4"
        launcher:numcolumns="5"
        launcher:numfolderrows="4"
        launcher:numfoldercolumns="5"
        launcher:iconsize="50"
        launcher:icontextsize="11"
        launcher:numhotseaticons="4"
        launcher:defaultlayoutid="@xml/default_workspace_tb_5x6_no_all_app"
        />

对应的你需要在 xml 文件下增加 4 个文件,分别是 default_workspace_tb_5x6.xml dw_hotseat_tb.xml default_workspace_tb_5x6_no_all_app.xml dw_hotseat_tb_no_all_app.xml

这样的好处是你可以自定义不同的布局文件加载内容,上面的配置含义简单说一下,分别是最小宽度、最小高度、布局的行和列、文件夹中布局行和列、图标大小、图标文字大小、hotseat 个数,加载的布局文件

在 invariantdeviceprofile() 判断是否需要加载 tablet_no_all_app profile

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\invariantdeviceprofile.java

public invariantdeviceprofile(context context) {

        windowmanager wm = (windowmanager) context.getsystemservice(context.window_service);
        display display = wm.getdefaultdisplay();
        displaymetrics dm = new displaymetrics();
        display.getmetrics(dm);

        point smallestsize = new point();
        point largestsize = new point();
        display.getcurrentsizerange(smallestsize, largestsize);

        // this guarantees that width < height
        minwidthdps = utilities.dpifrompx(math.min(smallestsize.x, smallestsize.y), dm);
        minheightdps = utilities.dpifrompx(math.min(largestsize.x, largestsize.y), dm);
        log.i("launcher3.profiles", "orignalminwidthdps="+minwidthdps + "  orignalminheightdps="+minheightdps);
        
        //add for load no_all_app xml
        if (launcherappstate.isdisableallapps()) {
            log.e("launcher3.profiles", "load no all app profiles");
            //对应 device_profiles.xml 中 tablet_no_all_app 的值
            minwidthdps = 380.0f;
            minheightdps = 590.0f;
        }
        .....
}

3、去除 allappsbutton

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\hotseat.java

将 resetlayout() 中 featureflags.no_all_apps_icon 替换为 launcherappstate.isdisableallapps()

void resetlayout(boolean hasverticalhotseat) {
        mcontent.removeallviewsinlayout();
        mhasverticalhotseat = hasverticalhotseat;
        invariantdeviceprofile idp = mlauncher.getdeviceprofile().inv;
        if (hasverticalhotseat) {
            mcontent.setgridsize(1, idp.numhotseaticons);
        } else {
            mcontent.setgridsize(idp.numhotseaticons, 1);
        }

        //if (!featureflags.no_all_apps_icon) {
        /// add for check is need allappbutton
        if (!launcherappstate.isdisableallapps()) {
            // add the apps button
            context context = getcontext();
            deviceprofile grid = mlauncher.getdeviceprofile();

        ...
}

4、将 allappscontainerview 中的图标加载到 workspace

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\model\loadertask.java

run() 中增加判断,添加 verifyapplications(), 修改 installshortcutreceiver 中 pendinginstallshortcutinfo 为 public

public void run() {
        synchronized (this) {
            // skip fast if we are already stopped.
            if (mstopped) {
                return;
            }
        }
        ....

        // second step
        tracehelper.partitionsection(tag, "step 2.1: loading all apps");
        loadallapps();

        //add for load all app on workspace
        if (launcherappstate.isdisableallapps()) {
            android.util.log.e("launcher3", "verifyapplications()");
            verifyapplications();
        }

        ....
}

 //add for load all app on workspace
private void verifyapplications() {
        final context context = mapp.getcontext();
        arraylist<pair<iteminfo, object>> installqueue = new arraylist<>();
        final list<userhandle> profiles = musermanager.getuserprofiles();
        for (userhandle user : profiles) {
            final list<launcheractivityinfo> apps = mlauncherapps.getactivitylist(null, user);
            arraylist<installshortcutreceiver.pendinginstallshortcutinfo> added = new arraylist<installshortcutreceiver.pendinginstallshortcutinfo>();
            synchronized (this) {
                for (launcheractivityinfo app : apps) {
                    installshortcutreceiver.pendinginstallshortcutinfo pendinginstallshortcutinfo = new installshortcutreceiver.pendinginstallshortcutinfo(app, context);
                    added.add(pendinginstallshortcutinfo);
                    installqueue.add(pendinginstallshortcutinfo.getiteminfo());
                }
            }
            if (!added.isempty()) {
                mapp.getmodel().addandbindaddedworkspaceitems(installqueue);
            }
        }
    }

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\model\basemodelupdatetask.java

注释 run() 中的 return

@override
    public final void run() {
        if (!mmodel.ismodelloaded()) {
            if (debug_tasks) {
                log.d(tag, "ignoring model task since loader is pending=" + this);
            }
            // loader has not yet run.
            //annotaion for load all app on workspace
            // return;
        }
        execute(mapp, mdatamodel, mallappslist);
    }

5、新安装的 app 自动添加图标到 workspace

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\model\packageupdatedtask.java

execute() 中增加判断,添加 updatetoworkspace()

public void execute(launcherappstate app, bgdatamodel datamodel, allappslist appslist) {

    ....

     final arraylist<appinfo> addedormodified = new arraylist<>();
    addedormodified.addall(appslist.added);
        
    //add for load new install app on workspace 
    if (launcherappstate.isdisableallapps()) {
        android.util.log.e("cczlauncher3", "updatetoworkspace()");
        updatetoworkspace(context, app, appslist);
    }
    
    ...
}

//add for load new install app on workspace
public void updatetoworkspace(context context, launcherappstate app , allappslist appslist){
         arraylist<pair<iteminfo, object>> installqueue = new arraylist<>();
        final list<userhandle> profiles = usermanagercompat.getinstance(context).getuserprofiles();
        arraylist<installshortcutreceiver.pendinginstallshortcutinfo> added 
        = new arraylist<installshortcutreceiver.pendinginstallshortcutinfo>();
        
        for (userhandle user : profiles) {
            final list<launcheractivityinfo> apps = launcherappscompat.getinstance(context).getactivitylist(null, user);
            synchronized (this) {
                for (launcheractivityinfo info : apps) {
                    for (appinfo appinfo : appslist.added) {
                        if(info.getcomponentname().equals(appinfo.componentname)){
                            installshortcutreceiver.pendinginstallshortcutinfo mpendinginstallshortcutinfo 
                            =  new installshortcutreceiver.pendinginstallshortcutinfo(info,context);
                            added.add(mpendinginstallshortcutinfo);
                            installqueue.add(mpendinginstallshortcutinfo.getiteminfo());
                        }
                    }
                }
            }
        }
        if (!added.isempty()) {
            app.getmodel().addandbindaddedworkspaceitems(installqueue);
        }
    }

6、替换 workspace 图标长按删除选项为取消

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\deletedroptarget.java

在 settextbasedondragsource() 、setcontroltypebasedondragsource()、onaccessibilitydrop() 中分别增加判断是否需要删除图标

private void settextbasedondragsource(iteminfo item) {
        if (!textutils.isempty(mtext)) {
            mtext = getresources().getstring(item.id != iteminfo.no_id
                    ? r.string.remove_drop_target_label
                    : android.r.string.cancel);
            //add for hide deletedroptarget
            if (launcherappstate.isdisableallapps()) {
                android.util.log.e("launcher3", "hide delete drop target");
                mtext = getresources().getstring(iscandrop(item)
                            ? r.string.remove_drop_target_label
                            : android.r.string.cancel);
            }

            requestlayout();
        }
    }

    private void setcontroltypebasedondragsource(iteminfo item) {
        mcontroltype = item.id != iteminfo.no_id ? controltype.remove_target
                : controltype.cancel_target;

        //add for hide deletedroptarget [s]
        if (launcherappstate.isdisableallapps()) {
            mcontroltype = iscandrop(item) ? controltype.remove_target
                : controltype.cancel_target;
        }        
    }

public void onaccessibilitydrop(view view, iteminfo item) {
        // remove the item from launcher and the db, we can ignore the containerinfo in this call
        // because we already remove the drag view from the folder (if the drag originated from
        // a folder) in folder.begindrag()
        //add if juge is need remove item from workspace
        if (!launcherappstate.isdisableallapps() || iscandrop(item)) {
            mlauncher.removeitem(view, item, true /* deletefromdb */);
            mlauncher.getworkspace().stripemptyscreens();
            mlauncher.getdraglayer()
                    .announceforaccessibility(getcontext().getstring(r.string.item_removed));
        }
}

private boolean iscandrop(iteminfo item){
        return !(item.itemtype == launchersettings.favorites.item_type_application ||
                item.itemtype == launchersettings.favorites.item_type_folder);
}

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\dragndrop\dragcontroller.java

drop() 中增加判断,取消当前拖拽操作

private void drop(droptarget droptarget, runnable flinganimation) {
    ....

    boolean accepted = false;
        if (droptarget != null) {
            droptarget.ondragexit(mdragobject);
            if (droptarget.acceptdrop(mdragobject)) {
                if (flinganimation != null) {
                    flinganimation.run();
                } else {
                    droptarget.ondrop(mdragobject, moptions);
                }
                accepted = true;

                //add for cancel canceldroptarget handle
                if (launcherappstate.isdisableallapps() && droptarget instanceof deletedroptarget &&
                        isneedcanceldrag(mdragobject.draginfo)) {
                    canceldrag();
                }
            }
        }
        ...
}

private boolean isneedcanceldrag(iteminfo item){
        return (item.itemtype == launchersettings.favorites.item_type_application ||
                item.itemtype == launchersettings.favorites.item_type_folder);
 }

7、屏蔽上拉显示抽屉页面手势

vendor\mediatek\proprietary\packages\apps\launcher3\quickstep\src\com\android\launcher3\uioverrides\overviewtoallappstouchcontroller.java

canintercepttouch() 中增加判断是否直接拦截

@override
    protected boolean canintercepttouch(motionevent ev) {
        //add for forbidden workspace drag change gradientview alph
        if (launcherappstate.isdisableallapps()){
            android.util.log.e("launcher3", "canintercepttouch()");
            return false;
        }  

        if (mcurrentanimation != null) {
            // if we are already animating from a previous state, we can intercept.
            return true;
        }
        if (abstractfloatingview.gettopopenview(mlauncher) != null) {
            return false;
        }
        if (mlauncher.isinstate(all_apps)) {
            // in all-apps only listen if the container cannot scroll itself
            return mlauncher.getappsview().shouldcontainerscroll(ev);
        } else if (mlauncher.isinstate(normal)) {
            return true;
        } else if (mlauncher.isinstate(overview)) {
            recentsview rv = mlauncher.getoverviewpanel();
            return ev.gety() > (rv.getbottom() - rv.getpaddingbottom());
        } else {
            return false;
        }
    }

8、修改页面指示线为圆点

vendor\mediatek\proprietary\packages\apps\launcher3\res\layout\launcher.xml

workspacepageindicator 改为 pageindicatordots

<com.android.launcher3.pageindicators.pageindicatordots
            android:id="@+id/page_indicator"
            android:layout_width="match_parent"
            android:layout_height="4dp"
            android:layout_gravity="bottom|center_horizontal"
            android:theme="@style/homescreenelementtheme" />

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\pageindicators\pageindicatordots.java

增加 pageindicatordots 继承 insettable,复写setinsets(), 调整圆点的位置

public class pageindicatordots extends view implements pageindicator, insettable {

// add for change workspacepageindicator line to dot
    @override
    public void setinsets(rect insets) {
        deviceprofile grid = mlauncher.getdeviceprofile();
        framelayout.layoutparams lp = (framelayout.layoutparams) getlayoutparams();

        if (grid.isverticalbarlayout()) {
            rect padding = grid.workspacepadding;
            lp.leftmargin = padding.left + grid.workspacecellpaddingxpx;
            lp.rightmargin = padding.right + grid.workspacecellpaddingxpx;
            lp.bottommargin = padding.bottom;
        } else {
            lp.leftmargin = lp.rightmargin = 0;
            lp.gravity = gravity.center_horizontal | gravity.bottom;
            lp.bottommargin = grid.hotseatbarsizepx + insets.bottom;
        }
        setlayoutparams(lp);
    }

    @override
    public void setscroll(int currentscroll, int totalscroll) {
        if (mnumpages > 1) {
            if (misrtl) {
                currentscroll = totalscroll - currentscroll;
            }
            int scrollperpage = totalscroll / (mnumpages - 1);

            // add for change workspacepageindicator line to dot
            if (scrollperpage == 0) {
                return;
            }
            int pagetoleft = currentscroll / scrollperpage;
            int pagetoleftscroll = pagetoleft * scrollperpage;
            int pagetorightscroll = pagetoleftscroll + scrollperpage;

        ...

}

vendor\mediatek\proprietary\packages\apps\launcher3\src\com\android\launcher3\states\springloadedstate.java

注释 setshouldautohide(),避免长按 workspace 时发生崩溃

@override
    public void onstateenabled(launcher launcher) {
        workspace ws = launcher.getworkspace();
        ws.showpageindicatoratcurrentscroll();
        //annotaion for workspacepageindicator line to dot
        // ws.getpageindicator().setshouldautohide(false);

        // prevent any un/installshortcutreceivers from updating the db while we are
        // in spring loaded mode
        installshortcutreceiver.enableinstallqueue(installshortcutreceiver.flag_drag_and_drop);
        launcher.getrotationhelper().setcurrentstaterequest(request_lock);
    }

    @override
    public void onstatedisabled(final launcher launcher) {
        //annotaion for workspacepageindicator line to dot
        // launcher.getworkspace().getpageindicator().setshouldautohide(true);

        // re-enable any un/installshortcutreceiver and now process any queued items
        installshortcutreceiver.disableandflushinstallqueue(
                installshortcutreceiver.flag_drag_and_drop, launcher);
    }

欢迎关注我的英文公众号【十句英文】,每日1首英文金曲+10句英文,伴你共同进步。

微信扫一扫下方二维码即可关注:

me71hs.jpg

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网