Android 7.0 Launcher3 removes app drawer

I did a project at the beginning of the year, and there was a requirement that the desktop should be turned into a single layer without a secondary menu. A few times recently, some friends have asked me this solution. Now I will share it with you.

First on the renderings:
write picture description here write picture description here

Functional decomposition

  1. Remove the Allapp button and adjust the HotSeat layout
  2. Put all applications on the first layer of the launcher
  3. Remove option to delete on long press

solution

1. Set the main switch
According to the mode of 6.0 Launcher3, add a switch to control whether to remove the drawer.

LauncherAppState class: singleton mode, mainly used at startup, it initializes some objects, and registers broadcast listeners and ContentObserver. In order to switch modes flexibly, add static switches to this class.

Launcher3\src\com\android\launcher3\LauncherAppState.java:

 public static boolean isDisableAllApps() {
        // Returns false on non-dogfood builds.
        return false;
    }

Second, the loading
of the Allapp key Remove the loading of the Allapp key in HotSeat, and shield isAllAppsButtonRank() to occupy the allapp position.

1) No longer occupy the allapp position
2) When loading the Workspace, the third position of HotSeat will be reserved for the allapp button. If the occupation of this position is not cancelled, a space will be left when HotSeat is loaded. The initialization of HotSeat is in HotSeat.java

Launcher3\src\com\android\launcher3\HotSeat.java –>isAllAppsButtonRank():

public boolean isAllAppsButtonRank(int rank) {

        //添加 @{
        if (LauncherAppState.isDisableAllApps()) {
            return false;
            }
        //添加 @}
        return rank == mAllAppsButtonRank;
    }

3) Home2 has no drawer, so no allapp button is needed. Remove the loading of the Allapp key in HotSeat, and initialize the HotSeat layout in void resetLayout() of HotSeat.java. Stop loading Allapp button at Home2.

Launcher3\src\com\android\launcher3\HotSeat.java –>resetLayout():

void resetLayout() {
        mContent.removeAllViewsInLayout();
        //添加 @{
        if(LauncherAppState.isDisableAllApps()){
        //添加 }@
        // Add the Apps button
        Context context = getContext();

        LayoutInflater inflater = LayoutInflater.from(context);
        TextView allAppsButton = (TextView)
                inflater.inflate(R.layout.all_apps_button, mContent, false);
        Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);

        mLauncher.resizeIconDrawable(d);
        allAppsButton.setCompoundDrawables(null, d, null, null);

        allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
        allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener());
        if (mLauncher != null) {
            mLauncher.setAllAppsButton(allAppsButton);
            allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
            allAppsButton.setOnClickListener(mLauncher);
            allAppsButton.setOnLongClickListener(mLauncher);
            allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
        }

        // Note: We do this to ensure that the hotseat is always laid out in the orientation of
        // the hotseat in order regardless of which orientation they were added
        int x = getCellXFromOrder(mAllAppsButtonRank);
        int y = getCellYFromOrder(mAllAppsButtonRank);
        CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1);
        lp.canReorder = false;
        mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
        }
    }//别漏了这里的 }

Third, change the HotSeat layout in the data initialization class

InvariantDeviceProfile.java Launcher3 is a class for layout initialization.

The number of Hotseat icons in HotSeat with the allapp button is five, and the number of Hotseat icons should be four without the allapp button.

Launcher3\src\com\android\launcher3\InvariantDeviceProfile.java:

1) First add a macro control

    //添加 @{
    private boolean hasDA = LauncherAppState.isDisableAllApps();
    //添加 }@

2) When the drawer is removed, the number of HotSeat is four, so an exception cannot be thrown. (no exception is thrown when numHotseatIcons is even)

InvariantDeviceProfile( ):

InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
        // Ensure that we have an odd number of hotseat items (since we need to place all apps)

        if (hs % 2 == 0&& !hasDA) {// 在无抽屉情况下不抛异常

            throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
        }

        name = n;
         ...   ...
    }

3) Load a different layout without the drawer

getPredefinedDeviceProfiles() :

ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
        ArrayList<InvariantDeviceProfile> predefinedDeviceProfiles = new ArrayList<>();
        // width, height, #rows, #columns, #folder rows, #folder columns,
        // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby",
                255, 300,     2, 3, 2, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby",
                255, 400,     3, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby",
                275, 420,     3, 4, 3, 4, 4, 48, 13, (hasDA ? 4 : 5), 48, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Stubby",
                255, 450,     3, 4, 3, 4, 4, 48, 13, (hasDA ? 4 : 5), 48, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus S",
                296, 491.33f, 4, 4, 4, 4, 4, 48, 13,(hasDA ? 4 : 5), 48, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
                335, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasDA ? 4 : 5), 56, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
                359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13,(hasDA ? 4 : 5), 56, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Large Phone",
                406, 694,     5, 5, 4, 4, 4, 64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
        // The tablet profile is odd in that the landscape orientation
        // also includes the nav bar on the side
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7",
                575, 904,     5, 6, 4, 5, 4, 72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
        // Larger tablet profiles always have system bars on the top & bottom
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10",
                727, 1207,    5, 6, 4, 5, 4, 76, 14.4f,  7, 64, R.xml.default_workspace_5x6));
        predefinedDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet",
                1527, 2527,   7, 7, 6, 6, 4, 100, 20,  7, 72, R.xml.default_workspace_4x4));
        return predefinedDeviceProfiles;
    }

5) Remember to change the layout of dw_phone_hotseat.xml, because Hotseat only has 5 grids.

Fourth, put all applications on the first layer

Launcher3 loading process: Enter LauncherApplication -> LauncherAppState -> to initialize the environment (by passing sContext). Do event listening && initialize some environment. For example: horizontal and vertical screen, local language, pixel density, widget and shortcut icon database operation object, application icon cache object, initialization LauncherMode, etc. After initialization, start with the Oncreate method of Launcher. Load data in mModel.startLoader(mWorkspace.getRestorePage());. After loading all the shortcuts, lay out the rest of the loaded application on the first layer.

1) After completing all the shortcuts, lay out the rest of the loaded applications on the first layer.

Launcher3\src\com\android\launcher3\LauncherModel.java:

LauncherModel$LoaderTask –> run():

public void run() {
            ... ...
            // Optimize for end-user experience: if the Launcher is up and // running with the
            // All Apps interface in the foreground, load All Apps first. Otherwise, load the
            // workspace first (default).
            keep_running: {
                if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
                loadAndBindWorkspace();

                if (mStopped) {
                    LauncherLog.i(TAG, "LoadTask break in the middle, this = " + this);
                    break keep_running;
                }

                waitForIdle();

                // second step
                if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
                loadAndBindAllApps();

                //添加 @{
                if (LauncherAppState.isDisableAllApps()) {
                    verifyApplications();
                }
                //添加 }@
            }

            // Clear out this reference, otherwise we end up holding it until all of the
            // callback runnables are done.
            ... ...
        }

Add verifyApplications():

private void verifyApplications() {
        final Context context = mApp.getContext();

        // Cross reference all the applications in our apps list with items in the workspace
        ArrayList<ItemInfo> tmpInfos;
        ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();
        synchronized (sBgLock) {
            for (AppInfo app : mBgAllAppsList.data) {
                tmpInfos = getItemInfoForComponentName(app.componentName, app.user);
                if (tmpInfos.isEmpty()) {
                    // We are missing an application icon, so add this to the workspace
                    added.add(app);
                    // This is a rare event, so lets log it
                    Log.e(TAG, "Missing Application on load: " + app);
                }
            }
        }
        if (!added.isEmpty()) {
            addAndBindAddedWorkspaceItems(context, added);//7.0 虽然去掉了去抽屉的代码,但留了这个方法给我们。
        }
    }

5. Update Workspace when new applications are added

When installing a new application, we need to update the left side to ensure that the installed application is added on the first layer.

Launcher3\src\com\android\launcher3\LauncherModel.java:

LauncherModel$PackageUpdatedTask –> run():

public void run() {
            if (!mHasLoaderCompletedOnce) {
                // Loader has not yet run.
                return;
            }
            final Context context = mApp.getContext();
            ... ...
            if (added != null) {
                // 添加 @{
                if(LauncherAppState.isDisableAllApps()){
                        final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);
                        addAndBindAddedWorkspaceItems(context, addedInfos);
                }else{
                // 添加 }@
                addAppsToAllApps(context, added);
                }
                for (AppInfo ai : added) {
                    addedOrUpdatedApps.put(ai.componentName, ai);
                }
            }
            ... ...
   }

Sixth, remove the delete option when long press

On long press, there should be no delete option.

DeleteDropTarget.java: Change the monitoring of long-press in , directly shield the delete button at the beginning, and later found that the shortcut issued by the application itself cannot be deleted, so the following processing is done.

Launcher3\src\com\android\launcher3\DeleteDropTarget.java –>supportsDrop():

public static boolean supportsDrop(Object info) {


         //添加 @{
        if (LauncherAppState.isDisableAllApps()) {             
            if (info instanceof ShortcutInfo) {           
                ShortcutInfo item = (ShortcutInfo) info;               
                return item.itemType != LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;                  
            }
            return info instanceof LauncherAppWidgetInfo;
        }
        //添加 }@
        return (info instanceof ShortcutInfo)
                || (info instanceof LauncherAppWidgetInfo)
                || (info instanceof FolderInfo);
    }

write at the end

At this point, the change of Launcher3 to remove the application drawer has been completed. There are still a lot of things we need to beautify, such as HotSeat layout adaptation and so on.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324943090&siteId=291194637