当前位置: 首页 > news >正文

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

核心修改如下:

public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {mAppsView = appsView;mScrimView = scrimView;// add startif (FeatureFlags.REMOVE_DRAWER) {mScrimView.setVisibility(View.GONE);}// add endPluginManagerWrapper.INSTANCE.get(mLauncher).addPluginListener(this, AllAppsSearchPlugin.class, false);
}

4.修改FeatureFlags:

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

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

核心修改如下:

添加一个变量控制是否显示抽屉
/*** 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方法中添加桌面图标是否取消拖拽

    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 startif (FeatureFlags.REMOVE_DRAWER) {if (dropTarget instanceof DeleteDropTarget && canCancel(mDragObject.dragInfo)) {cancelDrag();}}// add endaccepted = 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图标到桌面

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

@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 workspaceif (shortcutExists(dataModel, item.getIntent(), item.user)) {continue;}// b/139663018 Short-circuit this logic if the icon is a system app// add startif (!FeatureFlags.REMOVE_DRAWER) {// b/139663018 Short-circuit this logic if the icon is a system appif (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 dbgetModelWriter().addItemToDatabase(itemInfo,LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,coords[1], coords[2]);// Save the WorkspaceItemInfo for binding in the workspaceaddedItemsFinal.add(itemInfo);}}if (!addedItemsFinal.isEmpty()) {scheduleCallbackTask(new CallbackTask() {@Overridepublic 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

作用:

核心修改如下:

/*** 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 startif (FeatureFlags.REMOVE_DRAWER) {return false;}// add endfinal 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 containerreturn 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 otherif (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方法)

 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 breakwaitForIdle();logger.addSplit("step 1 complete");verifyNotStopped();// second stepList<LauncherActivityInfo> allActivityList = loadAllApps();logger.addSplit("loadAllApps");// add startif (FeatureFlags.REMOVE_DRAWER) {bindAllAppsToWorkspace();}// add endverifyNotStopped();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 breakwaitForIdle();logger.addSplit("step 2 complete");verifyNotStopped();// third stepList<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 breakwaitForIdle();logger.addSplit("step 3 complete");verifyNotStopped();// fourth stepList<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 stepif (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {loadFolderNames();}verifyNotStopped();updateHandler.finish();logger.addSplit("finish icon update");transaction.commit();} catch (CancellationException e) {// Loader stopped, ignorelogger.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方法中添加加载所有图标方法)

    @Overridepublic 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 atomicappsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());break;}}bindApplicationsIfNeeded();final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();// Update shortcut infosif (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 removedCollections.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 removedfinal 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 queueInstallShortcutReceiver.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 startif (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

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

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

@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 startif (FeatureFlags.REMOVE_DRAWER) {return false;}// add endif (mNoIntercept) {return false;}onControllerTouchEvent(ev);return mDetector.isDraggingOrSettling();
}

11.修改DeleteDropTarget:

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

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

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

private boolean canRemove(ItemInfo item) {// ad startboolean remove = FeatureFlags.REMOVE_DRAWER ? !canCancel(item): item.id != ItemInfo.NO_ID;// add endreturn 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

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

核心修改如下:

/*** 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 startif (FeatureFlags.REMOVE_DRAWER) {hotseatBarSizePx = 0;}// add endint 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 sizespadding.set(desiredWorkspaceLeftRightMarginPx,edgeMarginPx,desiredWorkspaceLeftRightMarginPx,paddingBottom);}}
}

13.修改Hotseat:

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

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

核心修改如下:

@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 startif (FeatureFlags.REMOVE_DRAWER) {lp.height = 0;}// add endsetLayoutParams(lp);InsettableFrameLayout.dispatchInsets(this, insets);
}

14.修改InvariantDeviceProfile:

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

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

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

private void initGrid(Context context, DefaultDisplay.Info displayInfo, DisplayOption displayOption) {GridOption closestProfile = displayOption.grid;numRows = closestProfile.numRows;numColumns = closestProfile.numColumns;// add startif (FeatureFlags.REMOVE_DRAWER) {numRows = 5;numColumns = 5;}// add endnumHotseatIcons = 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, iconSizeapplyPartnerDeviceProfileOverrides(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 effectsif (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.修改BaseModelUpdateTask:

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

作用:更新应用列表

核心修改如下:在启动时即加载全部APP而不是需要安装任一APP时才触发

@Override
public final void run() {if (!mModel.isModelLoaded()) {if (DEBUG_TASKS) {Log.d(TAG, "Ignoring model task since loader is pending=" + this);}// Loader has not yet run.// return;}execute(mApp, mDataModel, mAllAppsList);
}

16.实现效果如下:

在这里插入图片描述

17.总结:

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

  • 没有导包导致编译失败,这里由于源码太多没有给出所有源码,大家可以下载源码导包后自行编译.
  • 没有去掉过滤发发发导致系统图标没有显示
  • 没有在更新图标时加载所有图标导致新安装的系统应用没有显示
  • 没有去掉重复的图标和更新时的拖拽
  • 在数据库图标更新时发生崩溃异常,需要根据具体日志排查解决
  • 在编译源码的时候一定要仔细阅读,小心添加逻辑,加上注释避免后面问题排查困难.
http://www.xdnf.cn/news/988111.html

相关文章:

  • 汇编(cpu寄存器描述)
  • 字符串和内存函数(2)
  • MacBook M1 Pro下载安装MySql
  • Redis分布式缓存(RDB、AOF、主从同步)
  • force命令的使用
  • 图文教程——Deepseek最强平替工具免费申请教程——国内edu邮箱可用
  • 传统Web应用和RESTful API模式
  • javaee初阶-多线程
  • C++基础
  • Oracle集群OCR磁盘组掉盘问题处理
  • echart pie label.rich 颜色设置与项目同色
  • matlab红外与可见光图像配准算法
  • Flask 报错修复实战:send_file() got an unexpected keyword argument ‘etag‘
  • 什么是Power Distribution Unit(PDU)以及智能PDU:应用的演变历程
  • C#简单线程启动的几种方法总结
  • Windows平台网络通信
  • SQL Server 查询数据库中所有表中所有字段的数据类型及长度
  • 从“字对字“到“意对意“:AI翻译正在重塑人类的语言认知模式
  • 从代码学习深度学习 - 全局向量的词嵌入(GloVe)PyTorch版
  • 医疗行业双碳战略升维:从合规达标到价值创造的转型路径
  • JavaWeb(JavaBean预习)
  • 智慧园区智能化整体解决方案
  • c#实现绝对路径和相对路径的转换
  • 黑马python(四)
  • CentOS Stream 9——RustDesk基础版自建教程(Docker)
  • <script> 标签的 async 与 defer 属性详解
  • 《Linux C编程实战》笔记番外:如何避免子进程成为僵尸进程
  • 阿里云unbantu、Flask部署模型的一个错误
  • 安卓+苹果端签名教程
  • SiteAzure:文章删除后,前台还能搜索到