android Launcher3双层改单层

将Launcher3改为单层模式,这是android系统定制遇到的一个常见的需求。下面我将介绍一下我再MTK源码下将Luancher3改为单层的步骤和方法,以及解决一些bug。希望这个总结对读者有一点启发和用途。

一、打开Launcher3的单层开关

MTK源码的Launcher3本省就有单层开关。这个开关就是LauncherAppState.java的public static boolean isDisableAllApps()方法,只要把这个方法的返回值改为true即可。做好这一步,重新编译安装后,Launcher3就变为单层模式了。

二、虽然Launcher3变成了单层,但是带来了几个问题

1、重新启动Launcher3,安装一个第三方应用,这时应用可以被卸载;但是安装第三方应用后,再重启后就不能被卸载(长按不会出现卸载提示)。通过debug断点查看Launcher3的卸载过程,发现Launcher3是否能够删除主要是根据ShortcutInfo或Appinfo的flags来决定。但是,通过查看代码可以看到在LauncherModel.java(数据库操作类)通过方法getShortcutInfo获取ShortcutInfo时,flags没有被设置数字,一直为默认值0,因而无法删除应用。原生代码的两层UI对应的数据分别是ShortcutInfo和Appinfo,查询AppInfo时不同于ShortcutInfo,flags值会有赋值。同时,根据安装第三方应用后不重启可以被删除的情况判断,安装广播时得到新的ShoertcurInfo会对flags赋值。所以解决的办法就有了:修改getShortcutInfo方法,在方法中实现当isDisableAllApps == true时对flags进行赋值。赋值的方法参照对AppInfo的flags赋值的方法,最后方法如下:

try {
            final String packageName = componentName.getPackageName();
            PackageInfo pi = manager.getPackageInfo(packageName, 0);
            if (!pi.applicationInfo.enabled) {
                return null;
            }
            final int appFlags = manager.getApplicationInfo(packageName, 0).flags;
            if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
                info.flags |= AppInfo.DOWNLOADED_FLAG;
                if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
                    info.flags |= AppInfo.UPDATED_SYSTEM_APP_FLAG;
                }
            }
        } catch (NameNotFoundException e) {
            return null;
        }

。。。。。。。。。。。。。。。。。。。。。。

打包、安装、运行,还是报错了。。。。。

查看日志,发现问题是DeleteDropTarget.java下:


onDragStart(DragSource source, Object info, int dragAction)实现图标更换:增加判断条件
boolean useUninstallLabel = LauncherAppState.isDisableAllApps() &&
                (info instanceof ShortcutInfo);
        boolean useDeleteLabel = !useUninstallLabel && (info instanceof LauncherAppWidgetInfo);


completeDrop(DragObject d)实现卸载操作:将11111111111111处改为2222222222222222
else if (isWorkspaceOrFolderApplication(d)) {
            if (LauncherLog.DEBUG) {
            LauncherLog.d(TAG, "33isWorkspaceOrFolderApplication");
            }
            //LauncherModel.deleteItemFromDatabase(mLauncher, item);//1111111111111111111111
            ///{22222222222
            ShortcutInfo shortcut = (ShortcutInfo) item;
            ComponentName componentName = shortcut.intent.getComponent();
            AppInfo appInfo = (AppInfo) shortcut.makeAppInfo();
            mLauncher.startApplicationUninstallActivity(componentName, appInfo.flags,
                    appInfo.user);
            ///22222222222}        
       
private boolean isWorkspaceOrFolderApplication(DragObject d) {
        return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof ShortcutInfo);
  }

2、修改桌面为循环滚动:\packages\apps\Launcher3\ext\src\com\mediatek\launcher3\ext\DefaultWorkspaceExt.java
    @Override
    public boolean supportAppListCycleSliding() {
        LauncherLog.d(TAG, "default supportAppListCycleSliding called.");
        return true;
    }

3、修改后,添加appwidget后,workspace缩小后的状态不会变回来。解决的办法/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java下



    /**
     * Zoom the camera back into the workspace, hiding 'fromView'.
     * This is the opposite of showAppsCustomizeHelper.
     * @param animated If true, the transition will be animated.
     */
    private void hideAppsCustomizeHelper(Workspace.State toState, final boolean animated,
            final boolean springLoaded, final Runnable onCompleteRunnable) {

==================================此处没有修改=========================================
       

        if (animated && initialized) {
            ==================================此处没有修改=========================================
        } else {
                //yuanhcn add============================================================================================
                mStateAnimation = LauncherAnimUtils.createAnimatorSet();
            if (workspaceAnim != null) {
                mStateAnimation.play(workspaceAnim);
            }


            final AppsCustomizePagedView content = (AppsCustomizePagedView)
                    fromView.findViewById(R.id.apps_customize_pane_content);
            Log.i(TAG, "content visible: " + (content.getVisibility() == View.VISIBLE));
            Log.i(TAG, "mAppsCustomizeTabHost visible: " + (mAppsCustomizeTabHost.getVisibility() == View.VISIBLE));


            final View page = content.getPageAt(content.getNextPage());
            Log.i(TAG, "content.getNextPage: " + content.getNextPage());
            
            // We need to hide side pages of the Apps / Widget tray to avoid some ugly edge cases
            int count = content.getChildCount();
            for (int i = 0; i < count; i++) {
                View child = content.getChildAt(i);
                if (child != page) {
                    child.setVisibility(View.INVISIBLE);
                }
            }
            final View revealView = fromView.findViewById(R.id.fake_page);


            // hideAppsCustomizeHelper is called in some cases when it is already hidden
            // don't perform all these no-op animations. In particularly, this was causing
            // the all-apps button to pop in and out.
            if (fromView.getVisibility() == View.VISIBLE) {
                AppsCustomizePagedView.ContentType contentType = content.getContentType();
                final boolean isWidgetTray =
                        contentType == AppsCustomizePagedView.ContentType.Widgets;


                if (isWidgetTray) {
                    revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
                } else {
                    /*ltz modify begin*/
                    if(Launcher.DISABLE_APPLIST_WHITE_BG) {
                        revealView.setBackground(null);
                    } else {
                        revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
                    }
                    /*ltz modify end*/
                }


                int width = revealView.getMeasuredWidth();
                int height = revealView.getMeasuredHeight();
                float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);


                // Hide the real page background, and swap in the fake one
                revealView.setVisibility(View.VISIBLE);
                content.setPageBackgroundsVisible(false);


                
                //
yuanhcn add  final View allAppsButton = getAllAppsButton();replece allAppsButton by mHotseat
                final View allAppsButton = getHotseat();
                
                
                revealView.setTranslationY(0);
                int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
                        allAppsButton, null);


                float xDrift = 0;
                float yDrift = 0;
                if (material) {
                    yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1];
                    xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0];
                } else {
                    yDrift = 2 * height / 3;
                    xDrift = 0;
                }
                Log.i(TAG, "yDrift: " + yDrift + ",xDrift: " + xDrift + ", isWidgetTray: " + isWidgetTray);


                revealView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                TimeInterpolator decelerateInterpolator = material ?
                        new LogDecelerateInterpolator(100, 0) :
                        new DecelerateInterpolator(1f);


                // The vertical motion of the apps panel should be delayed by one frame
                // from the conceal animation in order to give the right feel. We correpsondingly
                // shorten the duration so that the slide and conceal end at the same time.
                ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
                        0, yDrift);
                panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
                panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
                panelDriftY.setInterpolator(decelerateInterpolator);
                mStateAnimation.play(panelDriftY);


                ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
                        0, xDrift);
                panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
                panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
                panelDriftX.setInterpolator(decelerateInterpolator);
              //  mStateAnimation.play(panelDriftX);


                if (isWidgetTray || !material) {
                    float finalAlpha = material ? 0.4f : 0f;
                    revealView.setAlpha(1f);
                    ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
                            1f, finalAlpha);
                    panelAlpha.setDuration(material ? revealDuration : 150);
                    panelAlpha.setInterpolator(decelerateInterpolator);
                    panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
                    mStateAnimation.play(panelAlpha);
                }


                if (page != null) {
                    page.setLayerType(View.LAYER_TYPE_HARDWARE, null);


                    ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(page, "translationY",
                            0, yDrift);
                 //   page.setTranslationY(0);
                    pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
                    pageDrift.setInterpolator(decelerateInterpolator);
                    pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
                 //   mStateAnimation.play(pageDrift);


                    page.setAlpha(1f);
                    ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(page, "alpha", 1f, 0f);
                    itemsAlpha.setDuration(/*100*/60);
                    itemsAlpha.setInterpolator(decelerateInterpolator);
                    mStateAnimation.play(itemsAlpha);
                }


                View pageIndicators = fromView.findViewById(R.id.apps_customize_page_indicator);
              //  pageIndicators.setAlpha(1f);
                pageIndicators.setAlpha(0f);
                ObjectAnimator indicatorsAlpha =
                        LauncherAnimUtils.ofFloat(pageIndicators, "alpha", 0f);
                indicatorsAlpha.setDuration(revealDuration);
                indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
              //  mStateAnimation.play(indicatorsAlpha);


                width = revealView.getMeasuredWidth();


                if (material) {
                    if (!isWidgetTray) {
                        allAppsButton.setVisibility(View.INVISIBLE);
                    }
                    int allAppsButtonSize = LauncherAppState.getInstance().
                            getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
                    float finalRadius = isWidgetTray ? 0 : allAppsButtonSize / 2;
                    Animator reveal =
                            LauncherAnimUtils.createCircularReveal(revealView, width / 2,
                                    height / 2, revealRadius, finalRadius);
                    reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
                    reveal.setDuration(revealDuration);
                    reveal.setStartDelay(itemsAlphaStagger);


                    reveal.addListener(new AnimatorListenerAdapter() {
                        public void onAnimationEnd(Animator animation) {
                            revealView.setVisibility(View.INVISIBLE);
                            if (!isWidgetTray) {
                                allAppsButton.setVisibility(View.VISIBLE);
                            }
                        }
                    });


                    mStateAnimation.play(reveal);
                }


                dispatchOnLauncherTransitionPrepare(fromView, animated, true);
                dispatchOnLauncherTransitionPrepare(toView, animated, true);
                mAppsCustomizeContent.stopScrolling();
            }


            mStateAnimation.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    fromView.setVisibility(View.GONE);
                    dispatchOnLauncherTransitionEnd(fromView, animated, true);
                    dispatchOnLauncherTransitionEnd(toView, animated, true);
                    if (onCompleteRunnable != null) {
                        onCompleteRunnable.run();
                    }


                    revealView.setLayerType(View.LAYER_TYPE_NONE, null);
                    if (page != null) {
                        page.setLayerType(View.LAYER_TYPE_NONE, null);
                    }
                    content.setPageBackgroundsVisible(true);
                    // Unhide side pages
                    int count = content.getChildCount();
                    for (int i = 0; i < count; i++) {
                        View child = content.getChildAt(i);
                        child.setVisibility(View.VISIBLE);
                    }


                    // Reset page transforms
                    if (page != null) {
                        page.setTranslationX(0);
                        page.setTranslationY(0);
                        page.setAlpha(1);
                    }
                    content.setCurrentPage(content.getNextPage());


                    mAppsCustomizeContent.updateCurrentPageScroll();


                    // This can hold unnecessary references to views.
                    mStateAnimation = null;
                }
            });


            final AnimatorSet stateAnimation = mStateAnimation;
            final Runnable startAnimRunnable = new Runnable() {
                public void run() {
                    // Check that mStateAnimation hasn't changed while
                    // we waited for a layout/draw pass
                    if (mStateAnimation != stateAnimation)
                        return;
                    dispatchOnLauncherTransitionStart(fromView, animated, false);
                    dispatchOnLauncherTransitionStart(toView, animated, false);


                    if (Utilities.isLmpOrAbove()) {
                        for (int i = 0; i < layerViews.size(); i++) {
                            View v = layerViews.get(i);
                            if (v != null) {
                                if (Utilities.isViewAttachedToWindow(v)) v.buildLayer();
                            }
                        }
                    }
                    mStateAnimation.start();
                }
            };
            fromView.post(startAnimRunnable);
                //
yuanhcnadd
        
                //
yuanhcn delete
//            fromView.setVisibility(View.GONE);
//            dispatchOnLauncherTransitionPrepare(fromView, animated, true);
//            dispatchOnLauncherTransitionStart(fromView, animated, true);
//            dispatchOnLauncherTransitionEnd(fromView, animated, true);
//            dispatchOnLauncherTransitionPrepare(toView, animated, true);
//            dispatchOnLauncherTransitionStart(toView, animated, true);
//            dispatchOnLauncherTransitionEnd(toView, animated, true);
                //
yuanhcn 
delete
        }
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 10.0中,Launcher3是一个默认的桌面启动器应用程序。默认情况下,Launcher3使用了多层桌面布局,由于每个应用程序的图标和小部件可以在不同的层级上进行放置,可以实现更多自定义和可玩性。 要将Launcher3修改单层布局,可以进行以下步骤: 首先,要修改Launcher3的源代码。打开Launcher3的项目文件,在代码中找到与多层布局相关的部分。一般上,这些代码与屏幕上的图标和小部件的位置确定有关。 接下来,需要将多层布局单层布局。这意味着所有的图标和小部件将只能放置在一个层级上,不能另行分层。可以将所有图标和小部件视为一个整体,进行单层布局的更。 在代码中找到与层级相关的代码,并进行相应的修改。可能涉及到图标和小部件的位置计算、绘制和触摸事件等。将多层布局的相关代码注释掉,或者删除,然后添加单层布局的代码。确保所有的图标和小部件都被正确地放置在单个层级上。 最后,重新编译和部署修改后的Launcher3应用程序。确保应用程序可以成功运行,并验证桌面布局是否变为单层。 通过以上步骤,就可以成功地将Android 10.0 Launcher3修改单层布局。需要注意的是,这种修改可能涉及较多的代码更,并且需要一定的编程经验和知识。如果对Android开发不熟悉,建议参考相关文档和指南,或咨询专业的开发人员进行帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值