OS: RK3568 Android11.0

现在的产品基本都是按照手机样式去做,所以需要把系统默认的Launcher样式,去掉抽屉改为单层显示,也就是把所有的app添加到workspace中。
以下修改是在设备横屏模式下进行

1.添加一个宏开关控制Launcher单双层显示

  • 源码: /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;

2.去掉Qsb

  • 源码: /packages/apps/Launcher3/src/com/android/launcher3/config/FeatureFlags.java
public static final boolean QSB_ON_FIRST_SCREEN = false/*!Utilities.isEinkProduct()*/;

将这个宏改为false,第一页顶部的搜索框就不会显示了

3.加载所有app到workspace中并排序

  • 源码:packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
 // add start
 import com.android.launcher3.allapps.AppInfoComparator;
 import android.util.Pair;
 // end
 
 public void run() {
     synchronized (this) {
         // Skip fast if we are already stopped.
         if (mStopped) {
             return;
         }
     }
     ...
     // second step
     List<LauncherActivityInfo> allActivityList = loadAllApps();
     logger.addSplit("loadAllApps");
     
     // add start
     if (FeatureFlags.REMOVE_DRAWER) {
         bindAllAppsToWorkspace();
     }
     // add end
     
     verifyNotStopped();
     mResults.bindAllApps();
     logger.addSplit("bindAllApps");
     ...
 }    

 // 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

loadAllApps()中会获取所有应用数据,在添加的bindAllAppsToWorkspace方法中将获取的应用数据按名称排序,然后调用addAndBindAddedWorkspaceItems方法开始app数据与workspace的绑定,处理逻辑在AddWorkspaceItemsTask中进行。

4.系统应用不在workspace中显示

  • 源码: /packages/apps/Launcher3/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
 @Override
 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
     if (mItemList.isEmpty()) {
         return;
     }
     ...
     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;
         }
         
         // 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
     }

在开始处理的时候会判断,如果是系统应用会被忽略,所以我们要把这步跳过去。

5.Hotseat中的应用不在workspace中显示

  • 源码:packages/apps/Launcher3/src/com/android/launcher3/model/LoaderCursor.java
 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);
		 ...

默认在hotseat中的应用不会被添加到workspace中,属于hotseat的应用的container值是-101,所以在此处根据宏做处理或者注释掉default_workspace_xx.xml中launcher:container=“-101”的项

6.所有应用不在第一页显示

  • 源码: /packages/apps/Launcher3/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
 protected int[] findSpaceForItem( LauncherAppState app, BgDataModel dataModel,
         IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY) {
         ...
         
        // Find appropriate space for the item.
        int screenId = 0;
        int[] cordinates = new int[2];
        boolean found = false;

        int screenCount = workspaceScreens.size();
        // First check the preferred screen.
        int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;
        // add start
        if (FeatureFlags.REMOVE_DRAWER) {
            preferredScreenIndex = 0;
        }
        // add end
        if (preferredScreenIndex < screenCount) {
            screenId = workspaceScreens.get(preferredScreenIndex);
            found = findNextAvailableIconSpaceInScreen(
                    app, screenItems.get(screenId), cordinates, spanX, spanY);
        }

这个方法是添加item到workspace中时判断当前页是否有空余位置的,按照上面修改使绑定数据从workspace第一页开始。

7.app数据变化时,更新workspace

  • 源码:/packages/apps/Launcher3/src/com/android/launcher3/model/PackageUpdatedTask.java
 @Override
 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
     final Context context = app.getContext();
     final IconCache iconCache = app.getIconCache();
     ...
     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

8.禁止上滑显示Allapp

  • 源码:/packages/apps/Launcher3/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
 @Override
 public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
     if (ev.getAction() == MotionEvent.ACTION_DOWN) {
         mNoIntercept = !canInterceptTouch(ev);
         if (mNoIntercept) {
             return false;
         }
         ...  
     }
     // add start
     if (FeatureFlags.REMOVE_DRAWER) {
         return false;
     }
     // add end

     if (mNoIntercept) {
         return false;
     }

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

9.调整UI,去掉hotseat和AllApp button

去掉hotseat和Allapp按钮调整布局,设置workspace的行列

9.1 隐藏AllApp button
  • 源码:packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsTransitionController.java
 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);
 }
9.2 去掉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();
     ...
     // add start
     if (FeatureFlags.REMOVE_DRAWER) {
         lp.height = 0;
     }
     // add end
     setLayoutParams(lp);
     InsettableFrameLayout.dispatchInsets(this, insets);
 }

直接设置hotseat的高为0

9.3 横屏下workspace界面item的标题不显示
  • 源码:/packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java
 // 横屏下进入这里,会隐藏workspace中item的title
 if (isVerticalBarLayout()) {
     // Always hide the Workspace text with vertical bar layout.
     adjustToHideWorkspaceLabels();
 }
 ...
 public boolean isVerticalBarLayout() {
     return isLandscape && transposeLayoutWithOrientation;
 }
 ...
 public Builder(Context context, InvariantDeviceProfile inv, DefaultDisplay.Info info) {
     mContext = context;
     mInv = inv;
     mInfo = info;
     // add start
     if (FeatureFlags.REMOVE_DRAWER) {
         mTransposeLayoutWithOrientation = false;
     } else {
         mTransposeLayoutWithOrientation = context.getResources()
                 .getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
     }
     // add end
 }

hotseat_transpose_layout_with_orientation为true,hotseat的位置会根据屏幕方向旋转改变,这里直接修改为false,相应的isVerticalBarLayout()方法也返回false。

9.4 调整workspace的item的图标和标题的距离
 private void updateIconSize(float scale, Resources res) {
     // Workspace
     ...
     if (iconDrawablePaddingPx > cellYPadding && !isVerticalLayout
             && !isMultiWindowMode) {
         // Ensures that the label is closer to its corresponding icon. This is not an issue
         // with vertical bar layout or multi-window mode since the issue is handled separately
         // with their calls to {@link #adjustToHideWorkspaceLabels}.
         cellHeightPx -= (iconDrawablePaddingPx - cellYPadding);
         iconDrawablePaddingPx = cellYPadding;
     }
     // add start
     if (FeatureFlags.REMOVE_DRAWER) {
         iconDrawablePaddingPx = 0;
     }
     // add end
     cellWidthPx = iconSizePx + iconDrawablePaddingPx;
9.5 调整workspace到屏幕底部的间隔距离
 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;
         ...
 }       
9.6. 修改workspace行列
  • 源码: packages/apps/Launcher3/src/com/android/launcher3/InvariantDeviceProfile.java
 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 = 7;
     }
     // add end

10.修改workspace中的应用和文件拖拽移除为取消

  • 源码:/packages/apps/Launcher3/src/com/android/launcher3/DeleteDropTarget.java
 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
  • 源码:/packages/apps/Launcher3/src/com/android/launcher3/dragndrop/DragController.java
 private void drop(DropTarget dropTarget, Runnable flingAnimation) {
      ...
      // 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;
            }
        }
        ...
 }
 
 // add start
 private boolean canCancel(ItemInfo item){
      return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
          item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
 } 
 //add end
06-10 22:34