当前位置:   article > 正文

【Launcher3系列】 Android 10 11 12 Launcher3 双层改成单层_android 11.0 launcher3双层改成单层

android 11.0 launcher3双层改成单层
1. 概述

Android系统的Launcher改造在国内算是一个不算很低频的需求,尤其是相当多的三方硬件设备以及部分手机厂商的个性化ROM等,受限于国内整体的开源环境,网上能找到相关的开发资源并不多,最近公司有相关业务需求的开发,就自己涉及到的改造点作一些分享。

通常我们遇到的第一个改造点就是去掉原生Launcher自带的底部”全部“图标以及上拉显示的全部APP列表样式,这个不太符合如今国人的操作习惯,而在实际的开发中,发现其涉及到的改造点有如下几个:

  • 去掉上拉展示列表

  • 去掉导航条下方的上拉箭头

  • 确保新安装的APP直接加载到桌面

  • 确保系统APP直接显示到桌面

  • 确保初次启动时即加载全部APP而不是需要安装任一APP时才触发

2. 涉及到的类及接口等

去掉上拉展示列表(方法不唯一,暂用最简单方式)

com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController
  • 1

去掉导航栏下方箭头

com.android.launcher3.view.ScrimView
  • 1

确保新安装的APP直接加载到桌面

com.android.launcher3.model.LoaderTask
com.android.launcher3.model.PackageUpdatedTask
com.android.launcher3.InstallShortcutReceiver
  • 1
  • 2
  • 3

确保系统APP直接显示到桌面

com.android.launcher3.model.AddWorkspaceItemsTask
  • 1

确保初次启动时即加载全部APP而不是需要安装任一APP时才触发

com.android.launcher3.model.BaseModelUpdateTask
  • 1
3. Show the code
  • 去掉上拉展示列表

    这个改动其实有更稳妥的方式,但如果你暂时没有上拉触发个性化交互的其它需求,可采用以下方式。(这里补充说明下,如果是横屏,可能需要改动OverviewToAllAppsTouchController,修改点相同)

    PortraitStatesTouchController.java

        @Override
        protected boolean canInterceptTouch(MotionEvent ev) {
    //移除竖向抽屉====start====
            if(true){
                return false;
            }
    //移除竖向抽屉====end====
            if (mCurrentAnimation != null) {
                if (mFinishFastOnSecondTouch) {
                    mCurrentAnimation.getAnimationPlayer().end();
                }
    
                AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
                if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()) {
                    // If we are already animating from a previous state, we can intercept as long as
                    // the touch is below the current all apps progress (to allow for double swipe).
                    return true;
                }
                // Otherwise, make sure everything is settled and don't intercept so they can scroll
                // recents, dismiss a task, etc.
                if (mAtomicAnim != null) {
                    mAtomicAnim.end();
                }
                return false;
            }
            if (mLauncher.isInState(ALL_APPS)) {
                // In all-apps only listen if the container cannot scroll itself
                if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
                    return false;
                }
            } else if (mLauncher.isInState(OVERVIEW)) {
                if (!mOverviewPortraitStateTouchHelper.canInterceptTouch(ev)) {
                    return false;
                }
            } else {
                // If we are swiping to all apps instead of overview, allow it from anywhere.
                boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
                // For all other states, only listen if the event originated below the hotseat height
                if (!interceptAnywhere && !isTouchOverHotseat(mLauncher, ev)) {
                    return false;
                }
            }
            if (getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE | TYPE_ALL_APPS_EDU) != null) {
                return false;
            }
            return true;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
  • 去掉导航条下方的上拉箭头

    在某些设备上可能受屏幕宽高比或其它影响,这个箭头可能不显示,但考虑兼容性还是建议加上处理,这里改完之后,调试时可能会发现有一个不影响运行的报错”ShortcutRequest: Failed to query for shortcuts“,源于缺失ensureShortcutPermission,当为默认启动器时,推断无此报错,可暂不处理。

    ScrimView.java

        private void updateDragHandleVisibility(@Nullable Drawable recycle) {
            boolean visible = shouldDragHandleBeVisible();
            boolean wasVisible = mDragHandle != null;
            if (visible != wasVisible) {
                if (visible) {
    //隐藏上拉箭头,这里取最小改动,永不展示该箭头====改动start====
                    mDragHandle = recycle != null ? recycle :
                            mLauncher.getDrawable(0);//R.drawable.drag_handle_indicator_shadow);
    //====改动end====
                    mDragHandle.setBounds(mDragHandleBounds);
    
                    updateDragHandleAlpha();
                } else {
                    mDragHandle = null;
                }
                invalidate();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 确保新安装的APP直接加载到桌面

    这里涉及到三个类的改动LoaderTask.java、PackageUpdatedTask.java、InstallShortReceiver.java。

    InstallShortReceiver.java,这个只是需要将静态内部类PendingInstallShortcutInfo的可见性改为public。

    LoaderTask.java

    public void run() {
            synchronized (this) {
                // Skip fast if we are already stopped.
                if (mStopped) {
                    return;
                }
            }
    
            Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
            TimingLogger logger = new TimingLogger(TAG, "run");
            try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
               
                //...//
    
                // fifth step
                if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
                    loadFolderNames();
                }
    
                verifyNotStopped();
                updateHandler.finish();
                logger.addSplit("finish icon update");
    
    //预制应用展示在Workspace区====改动start====
                verifyApplications();
    //====改动end====
    
                transaction.commit();
            } catch (CancellationException e) {
                // Loader stopped, ignore
                logger.addSplit("Cancelled");
            } finally {
                logger.dumpToLog();
            }
            TraceHelper.INSTANCE.endSection(traceToken);
        }
    
    //====增加方法====
    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<>();
                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);
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    PackageUpdatedTask.java

    @Override
        public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
            final Context context = app.getContext();
            final IconCache iconCache = app.getIconCache();
    
            final String[] packages = mPackages;
            final int N = packages.length;
            FlagOp flagOp = FlagOp.NO_OP;
            final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
            ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);
            final HashSet<ComponentName> removedComponents = new HashSet<>();
    
            //...//
    
            bindApplicationsIfNeeded();
    //====改动start====
            updateToWorkSpace(context,app,appsList);
    //====改动end====
    
            final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();
    
            //...//
    
            if (Utilities.ATLEAST_OREO && mOp == OP_ADD) {
                // Load widgets for the new package. Changes due to app updates are handled through
                // AppWidgetHost events, this is just to initialize the long-press options.
                for (int i = 0; i < N; i++) {
                    dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser));
                }
                bindUpdatedWidgets(dataModel);
            }
        }
    
    
    //添加方法===改动====
        //安装的app添加到workspace工作区
        public void updateToWorkSpace(Context context,LauncherAppState app,AllAppsList appsList){
            ArrayList<Pair<ItemInfo,Object>> installQueue = new ArrayList<>();
            UserManager mUserManager = app.getContext().getSystemService(UserManager.class);
            final List<UserHandle> profiles = mUserManager.getUserProfiles();
            ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added = new ArrayList<>();
            LauncherApps mLauncherApps = app.getContext().getSystemService(LauncherApps.class);
            for(UserHandle user : profiles){
                final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null,user);
                synchronized (this){
                    for(LauncherActivityInfo info :apps){
                        for(AppInfo appInfo:appsList.data){
                            String packageName = info.getComponentName().getPackageName();
                            if(info.getComponentName().equals(appInfo.componentName)){
                                if(DEBUG){
                                    Log.d(TAG,"updateToWorkSpace packageName: " + packageName);
                                }
                                InstallShortcutReceiver.PendingInstallShortcutInfo mPendingInstallShortcutInfo
                                        = new InstallShortcutReceiver.PendingInstallShortcutInfo(info,context);
                                added.add(mPendingInstallShortcutInfo);
                                installQueue.add(mPendingInstallShortcutInfo.getItemInfo());
                            }
                        }
                    }
                }
            }
            if(!added.isEmpty()){
                app.getModel().addAndBindAddedWorkspaceItems(installQueue);
            }
        }
    
        private WorkspaceItemInfo createWorkSpaceItemInfo(Intent data,UserHandle user,LauncherAppState app){
            if(data == null){
                Log.e(TAG,"Can't construct WorkspaceItemInfo with null data");
                return null;
            }
            Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
            String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
            Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
            if(null == intent){
                //If the intent is null ,return null as we can't construct a valid WorkspaceItemInfo
                return null;
            }
            final WorkspaceItemInfo info = new WorkspaceItemInfo();
            info.user = user;
            BitmapInfo iconInfo = null;
            LauncherIcons li = LauncherIcons.obtain(app.getContext());
            if(bitmap instanceof Bitmap){
                iconInfo = li.createIconBitmap((Bitmap) bitmap);
            }else{
                Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
                if(extra instanceof Intent.ShortcutIconResource){
                    info.iconResource = (Intent.ShortcutIconResource)extra;
                    iconInfo = li.createIconBitmap(info.iconResource);
                }
            }
            li.recycle();
            if(null == iconInfo){
                iconInfo = app.getIconCache().getDefaultIcon(info.user);
            }
            info.bitmap = iconInfo;
            info.title = Utilities.trim(name);
            info.contentDescription = app.getContext().getPackageManager().getUserBadgedLabel(info.title,info.user);
            info.intent = intent;
            return info;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
  • 确保系统APP直接显示到桌面

    经过上面的改动之后,运行发现预装的APP和安装的APP都可以显示,但是系统自带的APP如相册、通讯录等不见了,这里是因为原代码中将该部分APP过滤了,需要去掉

    AddWorkspaceItemsTask.java

    @Override
        public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
            if (mItemList.isEmpty()) {
                return;
            }
    
            final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
            final IntArray addedWorkspaceScreensFinal = new IntArray();
    
            synchronized(dataModel) {
                IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
    
                List<ItemInfo> filteredItems = new ArrayList<>();
                for (Pair<ItemInfo, Object> entry : mItemList) {
                    ItemInfo item = entry.first;
                    Log.e("item=====",item.toString());
                    if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
                            item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
                        // Short-circuit this logic if the icon exists somewhere on the workspace
                        if (shortcutExists(dataModel, item.getIntent(), item.user)) {
                            continue;
                        }
    
                        // b/139663018 Short-circuit this logic if the icon is a system app
    //去掉对系统app的忽略处理====改动start====
    //                    if (PackageManagerHelper.isSystemApp(app.getContext(), item.getIntent())) {
    //                        continue;
    //                    }
    //====改动end=====
                    }
    
                    if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                        if (item instanceof AppInfo) {
                            item = ((AppInfo) item).makeWorkspaceItem();
                        }
                    }
                    if (item != null) {
                        filteredItems.add(item);
                    }
                }
    
                InstallSessionHelper packageInstaller =
                        InstallSessionHelper.INSTANCE.get(app.getContext());
                LauncherApps launcherApps = app.getContext().getSystemService(LauncherApps.class);
    
                //...//
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
  • 确保初次启动时即加载全部APP而不是需要安装任一APP时才触发

    在完成以上处理之后会发现,运行完毕后并不能将所有APP铺展到桌面上,但执行任一APP的安装过程之后就会触发了,这里需要作一下处理

    BaseModelUpdateTask.java

        @Override
        public final void run() {
            //注掉这个判断,就能让初次启动就加载所有到workspace
            if (!mModel.isModelLoaded()) {
                if (DEBUG_TASKS) {
                    Log.d(TAG, "Ignoring model task since loader is pending=" + this);
                }
                // Loader has not yet run.
    //====改动start====
                //或者这里简单处理,注掉return,能让初次启动就加载所有到workspace,否则AddWorkspaceItemsTask的execute未执行
                //return;
    //====改动end====
            }
            execute(mApp, mDataModel, mAllAppsList);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
4. 结语

以上为将系统初始的双层屏改为单层涉及到的全部改动,供参考。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/787716
推荐阅读
相关标签
  

闽ICP备14008679号