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开发要复杂,编译的时候很久,所以需要阅读大量源码,有时候源码太多,不一定要看所有的,只要抓住关键点去看,搞明白其原理和流程,修改起来就会很顺利.

  • 没有导包导致编译失败,这里由于源码太多没有给出所有源码,大家可以下载源码导包后自行编译.
  • 没有去掉过滤发发发导致系统图标没有显示
  • 没有在更新图标时加载所有图标导致新安装的系统应用没有显示
  • 没有去掉重复的图标和更新时的拖拽
  • 在数据库图标更新时发生崩溃异常,需要根据具体日志排查解决
  • 在编译源码的时候一定要仔细阅读,小心添加逻辑,加上注释避免后面问题排查困难.
相关推荐
还鮟2 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡3 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi004 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil5 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你5 小时前
Android View的绘制原理详解
android
移动开发者1号8 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号8 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best13 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk13 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭18 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin