Android11 Launcher3去掉抽屉改为单层

Android11 Launcher3去掉抽屉改为单层

1.前言:

之前在Android12 Rom定制的时候实现过不去掉抽屉显示所有应用列表,今天来讲解下在Android11时实现去掉抽屉显示在桌面所有应用列表,这里Android9和11的系统源码都是不一样的,所以改动有所区别,本文先讲解Android11的修改方式.

2.修改的核心类如下:

复制代码
AllAppsTransitionController
FeatureFlags
DragController
AddWorkspaceItemsTask
LoaderCursor
LoaderTask
PackageUpdatedTask
AbstractStateChangeTouchController
DeleteDropTarget
DeviceProfile
Hotseat
InvariantDeviceProfile

3.修改AllAppsTransitionController

源码路径:packages/apps/launcher3/src/com/android/launcher3/allapps/AllAppsTransitionController.java

核心修改如下:

csharp 复制代码
public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {
    mAppsView = appsView;
    mScrimView = scrimView;
    // add start
    if (FeatureFlags.REMOVE_DRAWER) {
        mScrimView.setVisibility(View.GONE);
    }
    // add end
    PluginManagerWrapper.INSTANCE.get(mLauncher)
            .addPluginListener(this, AllAppsSearchPlugin.class, false);
}

4.修改FeatureFlags:

源码路径:packages/apps/launcher3/src/com/android/launcher3/config/FeatureFlags.java

作用:各种功能常量工具类

核心修改如下:

arduino 复制代码
添加一个变量控制是否显示抽屉
/**
 * true: All applications are displayed in the workspace. Turn off the display of the allapp list
 */
public static final boolean REMOVE_DRAWER  = true;

5.修改DragController:

源码路径:packages/apps/launcher3/src/com/android/launcher3/dragndrop/DragController.java

作用:控制桌面图标是否可以拖拽。

核心修改如下:

在DragController的drop方法中添加桌面图标是否取消拖拽

ini 复制代码
    private void drop(DropTarget dropTarget, Runnable flingAnimation) {
        final int[] coordinates = mCoordinatesTemp;
        mDragObject.x = coordinates[0];
        mDragObject.y = coordinates[1];
​
        // Move dragging to the final target.
        if (dropTarget != mLastDropTarget) {
            if (mLastDropTarget != null) {
                mLastDropTarget.onDragExit(mDragObject);
            }
            mLastDropTarget = dropTarget;
            if (dropTarget != null) {
                dropTarget.onDragEnter(mDragObject);
            }
        }
​
        mDragObject.dragComplete = true;
        if (mIsInPreDrag) {
            if (dropTarget != null) {
                dropTarget.onDragExit(mDragObject);
            }
            return;
        }
​
        // Drop onto the target.
        boolean accepted = false;
        if (dropTarget != null) {
            dropTarget.onDragExit(mDragObject);
            if (dropTarget.acceptDrop(mDragObject)) {
                if (flingAnimation != null) {
                    flingAnimation.run();
                } else {
                    dropTarget.onDrop(mDragObject, mOptions);
                }
                // add start
                if (FeatureFlags.REMOVE_DRAWER) {
                    if (dropTarget instanceof DeleteDropTarget && canCancel(mDragObject.dragInfo)) {
                        cancelDrag();
                    }
                }
                // add end
                accepted = true;
            }
        }
        final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
        mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView);
        dispatchDropComplete(dropTargetAsView, accepted);
    }
​
// add start
private boolean canCancel(ItemInfo item){
    return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
            item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
//add end

6.修改AddWorkspaceItemsTask:

源码路径:packages/apps/launcher3/src/com/android/launcher3/model/AddWorkspaceItemsTask.java

作用:添加App图标到桌面

核心修改如下:(不过滤系统和飞系统图标,显示所有的图标)

scss 复制代码
@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;
            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
                // add start
                if (!FeatureFlags.REMOVE_DRAWER) {
                    // b/139663018 Short-circuit this logic if the icon is a system app
                    if (PackageManagerHelper.isSystemApp(app.getContext(), item.getIntent())) {
                        continue;
                    }
                }
                // add 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);
​
        for (ItemInfo item : filteredItems) {
            // Find appropriate space for the item.
            int[] coords = findSpaceForItem(app, dataModel, workspaceScreens,
                    addedWorkspaceScreensFinal, item.spanX, item.spanY);
            int screenId = coords[0];
​
            ItemInfo itemInfo;
            if (item instanceof WorkspaceItemInfo || item instanceof FolderInfo ||
                    item instanceof LauncherAppWidgetInfo) {
                itemInfo = item;
            } else if (item instanceof AppInfo) {
                itemInfo = ((AppInfo) item).makeWorkspaceItem();
            } else {
                throw new RuntimeException("Unexpected info type");
            }
​
            if (item instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) item).isPromise()) {
                WorkspaceItemInfo workspaceInfo = (WorkspaceItemInfo) item;
                String packageName = item.getTargetComponent() != null
                        ? item.getTargetComponent().getPackageName() : null;
                if (packageName == null) {
                    continue;
                }
                SessionInfo sessionInfo = packageInstaller.getActiveSessionInfo(item.user,
                        packageName);
                List<LauncherActivityInfo> activities = launcherApps
                        .getActivityList(packageName, item.user);
                boolean hasActivity = activities != null && !activities.isEmpty();
​
                if (sessionInfo == null) {
                    if (!hasActivity) {
                        // Session was cancelled, do not add.
                        continue;
                    }
                } else {
                    workspaceInfo.setInstallProgress((int) sessionInfo.getProgress());
                }
​
                if (hasActivity) {
                    // App was installed while launcher was in the background,
                    // or app was already installed for another user.
                    itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user)
                            .makeWorkspaceItem();
​
                    if (shortcutExists(dataModel, itemInfo.getIntent(), itemInfo.user)) {
                        // We need this additional check here since we treat all auto added
                        // workspace items as promise icons. At this point we now have the
                        // correct intent to compare against existing workspace icons.
                        // Icon already exists on the workspace and should not be auto-added.
                        continue;
                    }
​
                    WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
                    wii.title = "";
                    wii.bitmap = app.getIconCache().getDefaultIcon(item.user);
                    app.getIconCache().getTitleAndIcon(wii,
                            ((WorkspaceItemInfo) itemInfo).usingLowResIcon());
                }
            }
​
            // Add the shortcut to the db
            getModelWriter().addItemToDatabase(itemInfo,
                    LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,
                    coords[1], coords[2]);
​
            // Save the WorkspaceItemInfo for binding in the workspace
            addedItemsFinal.add(itemInfo);
        }
    }
​
    if (!addedItemsFinal.isEmpty()) {
        scheduleCallbackTask(new CallbackTask() {
            @Override
            public void execute(Callbacks callbacks) {
                final ArrayList<ItemInfo> addAnimated = new ArrayList<>();
                final ArrayList<ItemInfo> addNotAnimated = new ArrayList<>();
                if (!addedItemsFinal.isEmpty()) {
                    ItemInfo info = addedItemsFinal.get(addedItemsFinal.size() - 1);
                    int lastScreenId = info.screenId;
                    for (ItemInfo i : addedItemsFinal) {
                        if (i.screenId == lastScreenId) {
                            addAnimated.add(i);
                        } else {
                            addNotAnimated.add(i);
                        }
                    }
                }
                callbacks.bindAppsAdded(addedWorkspaceScreensFinal,
                        addNotAnimated, addAnimated);
            }
        });
    }
}

7.修改LoaderCursor:

源码路径:packages/apps/launcher3/src/com/android/launcher3/model/LoaderCursor.java

作用:

核心修改如下:

kotlin 复制代码
/**
 * check & update map of what's occupied; used to discard overlapping/invalid items
 */
protected boolean checkItemPlacement(ItemInfo item) {
    int containerIndex = item.screenId;
    if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
        // add start
        if (FeatureFlags.REMOVE_DRAWER) {
            return false;
        }
        // add end
        final GridOccupancy hotseatOccupancy =
                occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
​
        if (item.screenId >= mIDP.numHotseatIcons) {
            Log.e(TAG, "Error loading shortcut " + item
                    + " into hotseat position " + item.screenId
                    + ", position out of bounds: (0 to " + (mIDP.numHotseatIcons - 1)
                    + ")");
            return false;
        }
​
        if (hotseatOccupancy != null) {
            if (hotseatOccupancy.cells[(int) item.screenId][0]) {
                Log.e(TAG, "Error loading shortcut into hotseat " + item
                        + " into position (" + item.screenId + ":" + item.cellX + ","
                        + item.cellY + ") already occupied");
                return false;
            } else {
                hotseatOccupancy.cells[item.screenId][0] = true;
                return true;
            }
        } else {
            final GridOccupancy occupancy = new GridOccupancy(mIDP.numHotseatIcons, 1);
            occupancy.cells[item.screenId][0] = true;
            occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
            return true;
        }
    } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
        // Skip further checking if it is not the hotseat or workspace container
        return true;
    }
​
    final int countX = mIDP.numColumns;
    final int countY = mIDP.numRows;
    if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
            item.cellX < 0 || item.cellY < 0 ||
            item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
        Log.e(TAG, "Error loading shortcut " + item
                + " into cell (" + containerIndex + "-" + item.screenId + ":"
                + item.cellX + "," + item.cellY
                + ") out of screen bounds ( " + countX + "x" + countY + ")");
        return false;
    }
​
    if (!occupied.containsKey(item.screenId)) {
        GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
        if (item.screenId == Workspace.FIRST_SCREEN_ID) {
            // Mark the first row as occupied (if the feature is enabled)
            // in order to account for the QSB.
            screen.markCells(0, 0, countX + 1, 1, FeatureFlags.QSB_ON_FIRST_SCREEN);
        }
        occupied.put(item.screenId, screen);
    }
    final GridOccupancy occupancy = occupied.get(item.screenId);
​
    // Check if any workspace icons overlap with each other
    if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) {
        occupancy.markCells(item, true);
        return true;
    } else {
        Log.e(TAG, "Error loading shortcut " + item
                + " into cell (" + containerIndex + "-" + item.screenId + ":"
                + item.cellX + "," + item.cellX + "," + item.spanX + "," + item.spanY
                + ") already occupied");
        return false;
    }
}

8.修改LoaderTask:

源码路径:packages/apps/launcher3/src/com/android/launcher3/model/LoaderTask.java

作用:加载桌面图标的线程

核心修改如下:(在加载桌面图标时如果是显示所有应用就不过滤图标,使用bindAllAppsToWorkspace方法)

scss 复制代码
 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)) {
            List<ShortcutInfo> allShortcuts = new ArrayList<>();
            loadWorkspace(allShortcuts);
            loadCachedPredictions();
            logger.addSplit("loadWorkspace");
​
            verifyNotStopped();
            mResults.bindWorkspace();
            logger.addSplit("bindWorkspace");
​
            // Notify the installer packages of packages with active installs on the first screen.
            sendFirstScreenActiveInstallsBroadcast();
            logger.addSplit("sendFirstScreenActiveInstallsBroadcast");
​
            // Take a break
            waitForIdle();
            logger.addSplit("step 1 complete");
            verifyNotStopped();
​
            // second step
            List<LauncherActivityInfo> allActivityList = loadAllApps();
            logger.addSplit("loadAllApps");
​
            // add start
            if (FeatureFlags.REMOVE_DRAWER) {
                bindAllAppsToWorkspace();
            }
            // add end
​
            verifyNotStopped();
            mResults.bindAllApps();
            logger.addSplit("bindAllApps");
​
            verifyNotStopped();
            IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
            setIgnorePackages(updateHandler);
            updateHandler.updateIcons(allActivityList,
                    LauncherActivityCachingLogic.newInstance(mApp.getContext()),
                    mApp.getModel()::onPackageIconsUpdated);
            logger.addSplit("update icon cache");
​
            if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
                verifyNotStopped();
                logger.addSplit("save shortcuts in icon cache");
                updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),
                        mApp.getModel()::onPackageIconsUpdated);
            }
​
            // Take a break
            waitForIdle();
            logger.addSplit("step 2 complete");
            verifyNotStopped();
​
            // third step
            List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
            logger.addSplit("loadDeepShortcuts");
​
            verifyNotStopped();
            mResults.bindDeepShortcuts();
            logger.addSplit("bindDeepShortcuts");
​
            if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
                verifyNotStopped();
                logger.addSplit("save deep shortcuts in icon cache");
                updateHandler.updateIcons(allDeepShortcuts,
                        new ShortcutCachingLogic(), (pkgs, user) -> { });
            }
​
            // Take a break
            waitForIdle();
            logger.addSplit("step 3 complete");
            verifyNotStopped();
​
            // fourth step
            List<ComponentWithLabelAndIcon> allWidgetsList =
                    mBgDataModel.widgetsModel.update(mApp, null);
            logger.addSplit("load widgets");
​
            verifyNotStopped();
            mResults.bindWidgets();
            logger.addSplit("bindWidgets");
            verifyNotStopped();
​
            updateHandler.updateIcons(allWidgetsList,
                    new ComponentWithIconCachingLogic(mApp.getContext(), true),
                    mApp.getModel()::onWidgetLabelsUpdated);
            logger.addSplit("save widgets in icon cache");
​
            // fifth step
            if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
                loadFolderNames();
            }
​
            verifyNotStopped();
            updateHandler.finish();
            logger.addSplit("finish icon update");
​
            transaction.commit();
        } catch (CancellationException e) {
            // Loader stopped, ignore
            logger.addSplit("Cancelled");
        } finally {
            logger.dumpToLog();
        }
        TraceHelper.INSTANCE.endSection(traceToken);
    }
​
// add start
private void bindAllAppsToWorkspace(){
    if (mBgAllAppsList.data.size() > 0) {
        AppInfoComparator mAppNameComparator = new AppInfoComparator(mApp.getContext());
        ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>(mBgAllAppsList.data);
        // 按照名称进行排序
        Collections.sort(appInfos, mAppNameComparator);
        ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
        for (AppInfo info : appInfos) {
            installQueue.add(Pair.create((ItemInfo) info, null));
        }
        mApp.getModel().addAndBindAddedWorkspaceItems(installQueue);
    }
}
// end

9.修改PackageUpdatedTask:

源码路径:packages/apps/launcher3/src/com/android/launcher3/model/PackageUpdatedTask.java

作用:在桌面App图标发生变化时的线程

核心修改如下:(如果显示所有图标时,在线程的execute方法中添加加载所有图标方法)

ini 复制代码
    @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<>();
​
        switch (mOp) {
            case OP_ADD: {
                for (int i = 0; i < N; i++) {
                    if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
                    String pkg = packages[i];
                    if ("com.android.calendar".equals(pkg)
                            || "com.android.deskclock".equals(pkg)
                            || "com.android.dialer".equals(pkg)
                            || "com.android.browser".equals(pkg)
                            || "com.android.contacts".equals(pkg)
                            || "com.android.camera2".equals(pkg)
                            || "com.android.email".equals(pkg)
                            || "com.android.calculator2".equals(pkg)
                            || "com.android.webview".equals(pkg)
                            || "com.android.gallery3d".equals(pkg)
                            || "com.android.music".equals(pkg)) {
                        continue;
                    }
                    iconCache.updateIconsForPkg(packages[i], mUser);
                    if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
                        appsList.removePackage(packages[i], mUser);
                    }
                    appsList.addPackage(context, packages[i], mUser);
​
                    // Automatically add homescreen icon for work profile apps for below O device.
                    if (!Utilities.ATLEAST_OREO && !Process.myUserHandle().equals(mUser)) {
                        SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);
                    }
                }
                flagOp = FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
                break;
            }
            case OP_UPDATE:
                try (SafeCloseable t =
                             appsList.trackRemoves(a -> removedComponents.add(a.componentName))) {
                    for (int i = 0; i < N; i++) {
                        if (DEBUG) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
                        String pkg = packages[i];
                        if ("com.android.calendar".equals(pkg)
                                || "com.android.deskclock".equals(pkg)
                                || "com.android.dialer".equals(pkg)
                                || "com.android.browser".equals(pkg)
                                || "com.android.contacts".equals(pkg)
                                || "com.android.camera2".equals(pkg)
                                || "com.android.email".equals(pkg)
                                || "com.android.calculator2".equals(pkg)
                                || "com.android.webview".equals(pkg)
                                || "com.android.gallery3d".equals(pkg)
                                || "com.android.music".equals(pkg)) {
                            continue;
                        }
                        iconCache.updateIconsForPkg(packages[i], mUser);
                        appsList.updatePackage(context, packages[i], mUser);
                        app.getWidgetCache().removePackage(packages[i], mUser);
                    }
                }
                // Since package was just updated, the target must be available now.
                flagOp = FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
                break;
            case OP_REMOVE: {
                for (int i = 0; i < N; i++) {
                    FileLog.d(TAG, "Removing app icon" + packages[i]);
                    iconCache.removeIconsForPkg(packages[i], mUser);
                }
                // Fall through
            }
            case OP_UNAVAILABLE:
                for (int i = 0; i < N; i++) {
                    if (DEBUG) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
                    appsList.removePackage(packages[i], mUser);
                    app.getWidgetCache().removePackage(packages[i], mUser);
                }
                flagOp = FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE);
                break;
            case OP_SUSPEND:
            case OP_UNSUSPEND:
                flagOp = mOp == OP_SUSPEND ?
                        FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED) :
                        FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED);
                if (DEBUG) Log.d(TAG, "mAllAppsList.(un)suspend " + N);
                appsList.updateDisabledFlags(matcher, flagOp);
                break;
            case OP_USER_AVAILABILITY_CHANGE: {
                UserManagerState ums = new UserManagerState();
                ums.init(UserCache.INSTANCE.get(context),
                        context.getSystemService(UserManager.class));
                flagOp = ums.isUserQuiet(mUser)
                        ? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER)
                        : FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER);
                // We want to update all packages for this user.
                matcher = ItemInfoMatcher.ofUser(mUser);
                appsList.updateDisabledFlags(matcher, flagOp);
​
                // We are not synchronizing here, as int operations are atomic
                appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
                break;
            }
        }
​
        bindApplicationsIfNeeded();
​
        final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();
​
        // Update shortcut infos
        if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
            final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
            final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>();
​
            // For system apps, package manager send OP_UPDATE when an app is enabled.
            final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
            synchronized (dataModel) {
                for (ItemInfo info : dataModel.itemsIdMap) {
                    if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
                        WorkspaceItemInfo si = (WorkspaceItemInfo) info;
                        boolean infoUpdated = false;
                        boolean shortcutUpdated = false;
​
                        // Update shortcuts which use iconResource.
                        if ((si.iconResource != null)
                                && packageSet.contains(si.iconResource.packageName)) {
                            LauncherIcons li = LauncherIcons.obtain(context);
                            BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
                            li.recycle();
                            if (iconInfo != null) {
                                si.bitmap = iconInfo;
                                infoUpdated = true;
                            }
                        }
​
                        ComponentName cn = si.getTargetComponent();
                        if (cn != null && matcher.matches(si, cn)) {
                            String packageName = cn.getPackageName();
​
                            if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
                                removedShortcuts.put(si.id, false);
                                if (mOp == OP_REMOVE) {
                                    continue;
                                }
                            }
​
                            if (si.isPromise() && isNewApkAvailable) {
                                boolean isTargetValid = true;
                                if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
                                    List<ShortcutInfo> shortcut =
                                            new ShortcutRequest(context, mUser)
                                                    .forPackage(cn.getPackageName(),
                                                            si.getDeepShortcutId())
                                                    .query(ShortcutRequest.PINNED);
                                    if (shortcut.isEmpty()) {
                                        isTargetValid = false;
                                    } else {
                                        si.updateFromDeepShortcutInfo(shortcut.get(0), context);
                                        infoUpdated = true;
                                    }
                                } else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
                                    isTargetValid = context.getSystemService(LauncherApps.class)
                                            .isActivityEnabled(cn, mUser);
                                }
                                if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
                                    if (updateWorkspaceItemIntent(context, si, packageName)) {
                                        infoUpdated = true;
                                    } else if (si.hasPromiseIconUi()) {
                                        removedShortcuts.put(si.id, true);
                                        continue;
                                    }
                                } else if (!isTargetValid) {
                                    removedShortcuts.put(si.id, true);
                                    FileLog.e(TAG, "Restored shortcut no longer valid "
                                            + si.getIntent());
                                    continue;
                                } else {
                                    si.status = WorkspaceItemInfo.DEFAULT;
                                    infoUpdated = true;
                                }
                            } else if (isNewApkAvailable && removedComponents.contains(cn)) {
                                if (updateWorkspaceItemIntent(context, si, packageName)) {
                                    infoUpdated = true;
                                }
                            }
​
                            if (isNewApkAvailable &&
                                    si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
                                iconCache.getTitleAndIcon(si, si.usingLowResIcon());
                                infoUpdated = true;
                            }
​
                            int oldRuntimeFlags = si.runtimeStatusFlags;
                            si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
                            if (si.runtimeStatusFlags != oldRuntimeFlags) {
                                shortcutUpdated = true;
                            }
                        }
​
                        if (infoUpdated || shortcutUpdated) {
                            updatedWorkspaceItems.add(si);
                        }
                        if (infoUpdated) {
                            getModelWriter().updateItemInDatabase(si);
                        }
                    } else if (info instanceof LauncherAppWidgetInfo && isNewApkAvailable) {
                        LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
                        if (mUser.equals(widgetInfo.user)
                                && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
                                && packageSet.contains(widgetInfo.providerName.getPackageName())) {
                            widgetInfo.restoreStatus &=
                                    ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY &
                                            ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
​
                            // adding this flag ensures that launcher shows 'click to setup'
                            // if the widget has a config activity. In case there is no config
                            // activity, it will be marked as 'restored' during bind.
                            widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
​
                            widgets.add(widgetInfo);
                            getModelWriter().updateItemInDatabase(widgetInfo);
                        }
                    }
                }
            }
​
            bindUpdatedWorkspaceItems(updatedWorkspaceItems);
            if (!removedShortcuts.isEmpty()) {
                deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false));
            }
​
            if (!widgets.isEmpty()) {
                scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
            }
        }
​
        final HashSet<String> removedPackages = new HashSet<>();
        if (mOp == OP_REMOVE) {
            // Mark all packages in the broadcast to be removed
            Collections.addAll(removedPackages, packages);
​
            // No need to update the removedComponents as
            // removedPackages is a super-set of removedComponents
        } else if (mOp == OP_UPDATE) {
            // Mark disabled packages in the broadcast to be removed
            final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
            for (int i=0; i<N; i++) {
                if (!launcherApps.isPackageEnabled(packages[i], mUser)) {
                    removedPackages.add(packages[i]);
                }
            }
        }
​
        if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
            ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
                    .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
                    .and(ItemInfoMatcher.ofItemIds(removedShortcuts, true));
            deleteAndBindComponentsRemoved(removeMatch);
​
            // Remove any queued items from the install queue
            InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser);
        }
​
        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);
        }
        // add start
        if (FeatureFlags.REMOVE_DRAWER) {
            bindAllAppsToWorkspace(app, appsList);
        }
        // add end
    }
​
// add start
private void bindAllAppsToWorkspace(LauncherAppState app, AllAppsList mBgAllAppsList){
    if (mBgAllAppsList.data.size() > 0) {
        //  AppInfoComparator mAppNameComparator = new AppInfoComparator(mApp.getContext());
        ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>(mBgAllAppsList.data);
        //  Collections.sort(appInfos, mAppNameComparator);
        ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
        for (AppInfo info : appInfos) {
            installQueue.add(Pair.create((ItemInfo) info, null));
        }
        app.getModel().addAndBindAddedWorkspaceItems(installQueue);
    }
}
// add end

10.修改AbstractStateChangeTouchController:

源码路径:packages/apps/launcher3/src/com/android/launcher3/touch/AbstractStateChangeTouchController

作用:控制桌面图标的触摸事件包含拖拽、删除、更新等

核心修改如下:(如果是单层时取消拖拽)

ini 复制代码
@Override
public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        mNoIntercept = !canInterceptTouch(ev);

        if (mNoIntercept) {
            return false;
        }

        // Now figure out which direction scroll events the controller will start
        // calling the callbacks.
        final int directionsToDetectScroll;
        boolean ignoreSlopWhenSettling = false;

        if (mCurrentAnimation != null) {
            directionsToDetectScroll = SingleAxisSwipeDetector.DIRECTION_BOTH;
            ignoreSlopWhenSettling = true;
        } else {
            directionsToDetectScroll = getSwipeDirection();
            if (directionsToDetectScroll == 0) {
                mNoIntercept = true;
                return false;
            }
        }
        mDetector.setDetectableScrollConditions(
                directionsToDetectScroll, ignoreSlopWhenSettling);
    }
    // add start
    if (FeatureFlags.REMOVE_DRAWER) {
        return false;
    }
    // add end
    if (mNoIntercept) {
        return false;
    }

    onControllerTouchEvent(ev);
    return mDetector.isDraggingOrSettling();
}

11.修改DeleteDropTarget:

源码路径:packages/apps/launcher3/src/com/android/launcher3/DeleteDropTarget.java

作用:桌面图标的删除事件处理

核心修改如下:(在单层时控制图标是否取消拖拽)

arduino 复制代码
private boolean canRemove(ItemInfo item) {
    // ad start
    boolean remove = FeatureFlags.REMOVE_DRAWER ? !canCancel(item)
            : item.id != ItemInfo.NO_ID;
    // add end
    return remove;
}

/**
 * Set mControlType depending on the drag item.
 */
private void setControlTypeBasedOnDragSource(ItemInfo item) {
    mControlType = (FeatureFlags.REMOVE_DRAWER ? !canCancel(item) :
            item.id != ItemInfo.NO_ID) ? ControlType.REMOVE_TARGET
            : ControlType.CANCEL_TARGET;
}

// add start
private boolean canCancel(ItemInfo item){
    return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
            item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
// add end

12.修改DeviceProfile:

源码路径:packages/apps/launcher3/src/com/android/launcher3/DeviceProfile.java

作用:控制桌面图标的间距

核心修改如下:

ini 复制代码
/**
 * Updates {@link #workspacePadding} as a result of any internal value change to reflect the
 * new workspace padding
 */
private void updateWorkspacePadding() {
    Rect padding = workspacePadding;
    if (isVerticalBarLayout()) {
        padding.top = 0;
        padding.bottom = edgeMarginPx;
        if (isSeascape()) {
            padding.left = hotseatBarSizePx;
            padding.right = hotseatBarSidePaddingStartPx;
        } else {
            padding.left = hotseatBarSidePaddingStartPx;
            padding.right = hotseatBarSizePx;
        }
    } else {
        // add start
        if (FeatureFlags.REMOVE_DRAWER) {
            hotseatBarSizePx = 0;
        }
        // add end
        int paddingBottom = hotseatBarSizePx + workspacePageIndicatorHeight
                - mWorkspacePageIndicatorOverlapWorkspace;
        if (isTablet) {
            // Pad the left and right of the workspace to ensure consistent spacing
            // between all icons
            // The amount of screen space available for left/right padding.
            int availablePaddingX = Math.max(0, widthPx - ((inv.numColumns * cellWidthPx) +
                    ((inv.numColumns - 1) * cellWidthPx)));
            availablePaddingX = (int) Math.min(availablePaddingX,
                    widthPx * MAX_HORIZONTAL_PADDING_PERCENT);
            int availablePaddingY = Math.max(0, heightPx - edgeMarginPx - paddingBottom
                    - (2 * inv.numRows * cellHeightPx) - hotseatBarTopPaddingPx
                    - hotseatBarBottomPaddingPx);
            padding.set(availablePaddingX / 2, edgeMarginPx + availablePaddingY / 2,
                    availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
        } else {
            // Pad the top and bottom of the workspace with search/hotseat bar sizes
            padding.set(desiredWorkspaceLeftRightMarginPx,
                    edgeMarginPx,
                    desiredWorkspaceLeftRightMarginPx,
                    paddingBottom);
        }
    }
}

13.修改Hotseat:

源码路径:packages/apps/launcher3/src/com/android/launcher3/Hotseat.java

作用:设置桌面图标显示的位置和宽高

核心修改如下:

ini 复制代码
@Override
public void setInsets(Rect insets) {
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
    DeviceProfile grid = mActivity.getDeviceProfile();

    if (grid.isVerticalBarLayout()) {
        lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
        if (grid.isSeascape()) {
            lp.gravity = Gravity.LEFT;
            lp.width = grid.hotseatBarSizePx + insets.left;
        } else {
            lp.gravity = Gravity.RIGHT;
            lp.width = grid.hotseatBarSizePx + insets.right;
        }
    } else {
        lp.gravity = Gravity.BOTTOM;
        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
        lp.height = grid.hotseatBarSizePx + insets.bottom;
    }
    Rect padding = grid.getHotseatLayoutPadding();
    setPadding(padding.left, padding.top, padding.right, padding.bottom);
    // add start
    if (FeatureFlags.REMOVE_DRAWER) {
        lp.height = 0;
    }
    // add end
    setLayoutParams(lp);
    InsettableFrameLayout.dispatchInsets(this, insets);
}

14.修改InvariantDeviceProfile:

源码路径:packages/apps/launcher3/src/com/android/launcher3/InvariantDeviceProfile

作用:控制桌面图标的排列样式

核心修改如下:(这里在单层时修改为5层行5列,真正的Launcher可以自定义为其他行数)

ini 复制代码
private void initGrid(
        Context context, DefaultDisplay.Info displayInfo, DisplayOption displayOption) {
    GridOption closestProfile = displayOption.grid;
    numRows = closestProfile.numRows;
    numColumns = closestProfile.numColumns;
    // add start
    if (FeatureFlags.REMOVE_DRAWER) {
        numRows = 5;
        numColumns = 5;
    }
    // add end
    numHotseatIcons = closestProfile.numHotseatIcons;
    dbFile = closestProfile.dbFile;
    defaultLayoutId = closestProfile.defaultLayoutId;
    demoModeLayoutId = closestProfile.demoModeLayoutId;
    numFolderRows = closestProfile.numFolderRows;
    numFolderColumns = closestProfile.numFolderColumns;
    numAllAppsColumns = closestProfile.numAllAppsColumns;

    mExtraAttrs = closestProfile.extraAttrs;

    iconSize = displayOption.iconSize;
    iconShapePath = getIconShapePath(context);
    landscapeIconSize = displayOption.landscapeIconSize;
    iconBitmapSize = ResourceUtils.pxFromDp(iconSize, displayInfo.metrics);
    iconTextSize = displayOption.iconTextSize;
    fillResIconDpi = getLauncherIconDensity(iconBitmapSize);

    if (Utilities.isGridOptionsEnabled(context)) {
        allAppsIconSize = displayOption.allAppsIconSize;
        allAppsIconTextSize = displayOption.allAppsIconTextSize;
    } else {
        allAppsIconSize = iconSize;
        allAppsIconTextSize = iconTextSize;
    }

    // If the partner customization apk contains any grid overrides, apply them
    // Supported overrides: numRows, numColumns, iconSize
    applyPartnerDeviceProfileOverrides(context, displayInfo.metrics);

    Point realSize = new Point(displayInfo.realSize);
    // The real size never changes. smallSide and largeSide will remain the
    // same in any orientation.
    int smallSide = Math.min(realSize.x, realSize.y);
    int largeSide = Math.max(realSize.x, realSize.y);

    DeviceProfile.Builder builder = new DeviceProfile.Builder(context, this, displayInfo)
            .setSizeRange(new Point(displayInfo.smallestSize),
                    new Point(displayInfo.largestSize));

    landscapeProfile = builder.setSize(largeSide, smallSide).build();
    portraitProfile = builder.setSize(smallSide, largeSide).build();

    // We need to ensure that there is enough extra space in the wallpaper
    // for the intended parallax effects
    if (context.getResources().getConfiguration().smallestScreenWidthDp >= 720) {
        defaultWallpaperSize = new Point(
                (int) (largeSide * wallpaperTravelToScreenWidthRatio(largeSide, smallSide)),
                largeSide);
    } else {
        defaultWallpaperSize = new Point(Math.max(smallSide * 2, largeSide), largeSide);
    }

    ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());
    defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
}

15.实现效果如下:

16.总结:

以上就是今天的内容修改Android11 launcher3桌面图标的样式去掉抽屉显示所有应用列表,这其中遇到很多问题,但是最后都通过仔细排查和日志解决了,源码修改和编译其实还是很有意思的,排查起来比App开发要复杂,编译的时候很久,所以需要阅读大量源码,有时候源码太多,不一定要看所有的,只要抓住关键点去看,搞明白其原理和流程,修改起来就会很顺利.

  • 没有导包导致编译失败,这里由于源码太多没有给出所有源码,大家可以下载源码导包后自行编译.
  • 没有去掉过滤发发发导致系统图标没有显示
  • 没有在更新图标时加载所有图标导致新安装的系统应用没有显示
  • 没有去掉重复的图标和更新时的拖拽
  • 在数据库图标更新时发生崩溃异常,需要根据具体日志排查解决
  • 在编译源码的时候一定要仔细阅读,小心添加逻辑,加上注释避免后面问题排查困难.
相关推荐
开发之奋斗人生6 小时前
android关于pthread的使用过程
android·pthread
wu_android8 小时前
Android 视图系统入门指南
android
淡淡的香烟8 小时前
Android11 Launcher3实现去掉抽屉改为单层
android
火柴就是我8 小时前
每日见闻之THREE.PerspectiveCamera的含义
android
小书房9 小时前
Android的Dalvik和ART
android·aot·jit·art·dalvik
夏日玲子9 小时前
Monkey 测试的基本概念及常用命令(Android )
android
whysqwhw9 小时前
Transcoder代码学习-项目构建
android
夕泠爱吃糖10 小时前
Linux 文件内容的查询与统计
android·linux·c#
yzpyzp10 小时前
Kotlin的MutableList和ArrayList区别
android·kotlin
用户20187928316710 小时前
故事:《安卓公司的消息快递系统》
android