Android 13(T) modifies single-layer desktop (Launcher3)

If Launcher wants to modify the single-layer desktop, there are three places that need to be modified.

  1. Block Cancel Swipe up to show all apps
  2. Automatically load application icons to a single-layer desktop, including startup and subsequent installed applications
  3. Remove the “remove” button of long-press desktop icon
1. Block and cancel and swipe up to show all apps
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 9016c1bea6..d50e062396 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
 + + + b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -69,9 + 69,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
             // Otherwise, don't intercept so they can scroll recents, dismiss a task, etc.
             return false;
         }
- if (LauncherAppState.isUserSingleLayerStyle() & amp; & amp; mLauncher.isInState(NORMAL)) {
- return false;
- }
         if (mLauncher.isInState(ALL_APPS)) {
             // In all-apps only listen if the container cannot scroll itself
             if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
@@ -100,6 + 97,9 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
         } else if (fromState == OVERVIEW) {
             return isDragTowardPositive ? OVERVIEW : NORMAL;
         } else if (fromState == NORMAL & amp; & amp; isDragTowardPositive) {
 + if (LauncherAppState.isUserSingleLayerStyle()) {
 + return fromState;
 + }
             return ALL_APPS;
         }
2. Automatically load application icons to the single-layer desktop, including startup and subsequent installed applications
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 33eed47236..a80de99614 100644
--- a/src/com/android/launcher3/LauncherAppState.java
 + + + b/src/com/android/launcher3/LauncherAppState.java
@@ -226,4 + 226,8 @@ public class LauncherAppState implements SafeCloseable {
             }
         }
     }
 +
 + public static boolean isUserSingleLayerStyle() {
 + return true;
 + }
 }
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 0d978e1b23..df0d629b83 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
 + + + b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -104,8 + 104,13 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
                         continue;
                     }
 
 + boolean mForceAdd = false;
 + if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
 + & amp; & amp; item instanceof WorkspaceItemInfo) {
 + mForceAdd = ((WorkspaceItemInfo) item).hasExtraFlag(WorkspaceItemInfo.EXTRA_FLAG_FORCE_ADD);
 + }
                     // b/139663018 Short-circuit this logic if the icon is a system app
- if (PackageManagerHelper.isSystemApp(app.getContext(),
 + if (!mForceAdd & amp; & amp; PackageManagerHelper.isSystemApp(app.getContext(),
                             Objects.requireNonNull(item.getIntent()))) {
                         if (TestProtocol.sDebugTracing) {
                             Log.d(TestProtocol.MISSING_PROMISE_ICON,
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index b0f6e13ae3..54997fff9f 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
 + + + b/src/com/android/launcher3/model/BgDataModel.java
@@ -404,6 + 404,12 @@ public class BgDataModel {
         return items;
     }
 
 + public synchronized ArrayList<ItemInfo> getAllWorkspaceItemsWithoutAppWidget() {
 + ArrayList<ItemInfo> items = new ArrayList<>(workspaceItems.size());
 + items.addAll(workspaceItems);
 + return items;
 + }
 +
     /**
      * Calls the provided {@code op} for all workspaceItems in the in-memory model (both persisted
      * items and dynamic/predicted items for the provided {@code userHandle}.
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 69f9b53090..b21bb91650 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
 + + + b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -187,6 + 187,13 @@ public class ItemInstallQueue {
         queuePendingShortcutInfo(new PendingInstallShortcutInfo(packageName, userHandle));
     }
 
 + /**
 + * Adds an item to the install queue
 + */
 + public void queueItem(LauncherActivityInfo launcherActivityInfo, UserHandle userHandle) {
 + queuePendingShortcutInfo(new PendingInstallShortcutInfo(launcherActivityInfo, userHandle));
 + }
 +
     /**
      * Returns a stream of all pending shortcuts in the queue
      */
@@ -251,6 + 258,8 @@ public class ItemInstallQueue {
 
         final Intent intent;
 
 + LauncherActivityInfo activityInfo = null;
 +
         @Nullable ShortcutInfo shortcutInfo;
         @Nullable AppWidgetProviderInfo providerInfo;
 
@@ -263,6 + 272,13 @@ public class ItemInstallQueue {
             user = userHandle;
         }
 
 + public PendingInstallShortcutInfo(LauncherActivityInfo activityInfo, UserHandle userHandle) {
 + itemType = Favorites.ITEM_TYPE_APPLICATION;
 + intent = new Intent().setComponent(activityInfo.getComponentName());
 + this.activityInfo = activityInfo;
 + user = userHandle;
 + }
 +
         /**
          * Initializes a PendingInstallShortcutInfo to represent a deep shortcut.
          */
@@ -293,6 + 309,33 @@ public class ItemInstallQueue {
             return intent;
         }
 
 + @Override
 + public boolean equals(Object obj) {
 + if (obj instanceof PendingInstallShortcutInfo) {
 + PendingInstallShortcutInfo other = (PendingInstallShortcutInfo) obj;
 +
 + boolean userMatches = user.equals(other.user);
 + boolean itemTypeMatches = itemType == other.itemType;
 + boolean intentMatches = intent.toUri(0).equals(other.intent.toUri(0));
 + boolean shortcutInfoMatches = shortcutInfo == null
 + ? other.shortcutInfo == null
 + : other.shortcutInfo != null
 + & amp; & amp; shortcutInfo.getId().equals(other.shortcutInfo.getId())
 + & amp; & amp; shortcutInfo.getPackage().equals(other.shortcutInfo.getPackage());
 + boolean providerInfoMatches = providerInfo == null
 + ? other.providerInfo == null
 + : other.providerInfo != null
 + & amp; & amp; providerInfo.provider.equals(other.providerInfo.provider);
 +
 + return userMatches
 + & amp; & amp; itemTypeMatches
 + & amp; & amp; intentMatches
 + & amp; & amp; shortcutInfoMatches
 + & amp; & amp; providerInfoMatches;
 + }
 + return false;
 + }
 +
         public Pair<ItemInfo, Object> getItemInfo(Context context) {
             switch (itemType) {
                 case ITEM_TYPE_APPLICATION: {
@@ -306,6 + 349,11 @@ public class ItemInstallQueue {
                     si.itemType = ITEM_TYPE_APPLICATION;
 
                     LauncherActivityInfo lai;
 + if (activityInfo != null) {
 + laiList.clear();
 + laiList.add(activityInfo);
 + si.addExtraFlag(WorkspaceItemInfo.EXTRA_FLAG_FORCE_ADD);
 + }
                     boolean usePackageIcon = laiList.isEmpty();
                     if (usePackageIcon) {
                         lai = null;
@@ -343,33 + 391,6 @@ public class ItemInstallQueue {
             }
             return null;
         }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof PendingInstallShortcutInfo) {
- PendingInstallShortcutInfo other = (PendingInstallShortcutInfo) obj;
-
- boolean userMatches = user.equals(other.user);
- boolean itemTypeMatches = itemType == other.itemType;
- boolean intentMatches = intent.toUri(0).equals(other.intent.toUri(0));
- boolean shortcutInfoMatches = shortcutInfo == null
- ? other.shortcutInfo == null
- : other.shortcutInfo != null
- & amp; & amp; shortcutInfo.getId().equals(other.shortcutInfo.getId())
- & amp; & amp; shortcutInfo.getPackage().equals(other.shortcutInfo.getPackage());
- boolean providerInfoMatches = providerInfo == null
- ? other.providerInfo == null
- : other.providerInfo != null
- & amp; & amp; providerInfo.provider.equals(other.providerInfo.provider);
-
- return userMatches
- & amp; & amp; itemTypeMatches
- & amp; & amp; intentMatches
- & amp; & amp; shortcutInfoMatches
- & amp; & amp; providerInfoMatches;
- }
- return false;
- }
     }
 
     private static String getIntentPackage(Intent intent) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 1d6971e27d..f0861e1697 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
 + + + b/src/com/android/launcher3/model/LoaderTask.java
@@ -117,6 + 117,7 @@ public class LoaderTask implements Runnable {
     private static final String TAG = "LoaderTask";
 
     private static final boolean DEBUG = true;
 + private static final boolean DEBUG_BOBO = true;
 
     protected final LauncherAppState mApp;
     private final AllAppsList mBgAllAppsList;
@@ -186,6 + 187,21 @@ public class LoaderTask implements Runnable {
 
         filterCurrentWorkspaceItems(firstScreens, allItems, firstScreenItems,
                 new ArrayList<>() /* otherScreenItems are ignored */);
 +
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "sendFirstScreenActiveInstallsBroadcast firstScreenItems size: "
 + + firstScreenItems.size());
 + for (ItemInfo itemInfo : firstScreenItems) {
 + Log.d(TAG, "firstScreenItems: " + itemInfo);
 + }
 + Log.d(TAG, "sendFirstScreenActiveInstallsBroadcast firstScreenItems end");
 + Log.d(TAG, "sendFirstScreenActiveInstallsBroadcast allItems size: "
 + + allItems.size());
 + for (ItemInfo itemInfo : allItems) {
 + Log.d(TAG, "allItems: " + itemInfo);
 + }
 + Log.d(TAG, "sendFirstScreenActiveInstallsBroadcast allItems end");
 + }
         mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
     }
 
@@ -196,6 + 212,9 @@ public class LoaderTask implements Runnable {
                 return;
             }
         }
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "run start");
 + }
 
         Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
         TimingLogger logger = new TimingLogger(TAG, "run");
@@ -208,6 + 227,13 @@ public class LoaderTask implements Runnable {
             } finally {
                 Trace.endSection();
             }
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "shortcutInfo size: " + allShortcuts.size());
 + for (ShortcutInfo shortcutInfo : allShortcuts) {
 + Log.d(TAG, "shortcutInfo: " + shortcutInfo);
 + }
 + Log.d(TAG, "shortcutInfo end");
 + }
             logASplit(logger, "loadWorkspace");
 
             // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
@@ -242,6 + 268,13 @@ public class LoaderTask implements Runnable {
             } finally {
                 Trace.endSection();
             }
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "allActivityList size: " + allActivityList.size());
 + for (LauncherActivityInfo activityInfo : allActivityList) {
 + Log.d(TAG, "activityInfo: " + activityInfo.getComponentName());
 + }
 + Log.d(TAG, "allActivityList end");
 + }
             logASplit(logger, "loadAllApps");
 
             verifyNotStopped();
@@ -268,6 + 301,13 @@ public class LoaderTask implements Runnable {
 
             // third step
             List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "allDeepShortcuts size: " + allDeepShortcuts.size());
 + for (ShortcutInfo shortcutInfo : allDeepShortcuts) {
 + Log.d(TAG, "shortcutInfo: " + shortcutInfo);
 + }
 + Log.d(TAG, "allDeepShortcuts end");
 + }
             logASplit(logger, "loadDeepShortcuts");
 
             verifyNotStopped();
@@ -287,6 + 327,13 @@ public class LoaderTask implements Runnable {
             // fourth step
             List<ComponentWithLabelAndIcon> allWidgetsList =
                     mBgDataModel.widgetsModel.update(mApp, null);
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "allWidgetsList size: " + allWidgetsList.size());
 + for (ComponentWithLabelAndIcon componentWithLabelAndIcon : allWidgetsList) {
 + Log.d(TAG, "componentWithLabelAndIcon: " + componentWithLabelAndIcon.getComponent());
 + }
 + Log.d(TAG, "allWidgetsList end");
 + }
             logASplit(logger, "load widgets");
 
             verifyNotStopped();
@@ -306,6 + 353,9 @@ public class LoaderTask implements Runnable {
             updateHandler.finish();
             logASplit(logger, "finish icon update");
 
 + // add apps for single layer--bobo
 + updateForSingleLayerStyle(allActivityList);
 +
             mModelDelegate.modelLoadComplete();
             transaction.commit();
             memoryLogger.clearLogs();
@@ -318,9 + 368,56 @@ public class LoaderTask implements Runnable {
         } finally {
             logger.dumpToLog();
         }
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "run end");
 + }
         TraceHelper.INSTANCE.endSection(traceToken);
     }
 
 + private void updateForSingleLayerStyle(List<LauncherActivityInfo> allActivityList) {
 + if (!LauncherAppState.isUserSingleLayerStyle()) {
 + return;
 + }
 + if (allActivityList == null || allActivityList.size() <= 0) {
 + return;
 + }
 + Map<String, LauncherActivityInfo> newAppsMap = new HashMap<>();
 + for (LauncherActivityInfo info : allActivityList) {
 + newAppsMap.put(getComponentKey(info.getComponentName(), info.getUser().getIdentifier()),
 +info);
 + }
 + ArrayList<ItemInfo> addedItems = mBgDataModel.getAllWorkspaceItemsWithoutAppWidget();
 + for (ItemInfo info : addedItems) {
 + if (info.getTargetComponent() == null) continue;
 + if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
 + newAppsMap.remove(getComponentKey(info.getTargetComponent(), info.user.getIdentifier()));
 + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
 + //TODO
 + }
 + }
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "updateForSingleLayerStyle newAppsMap:" + newAppsMap.size());
 + newAppsMap.values().stream().forEach(item->{
 + Log.d(TAG, "updateForSingleLayerStyle activityInfo: " + item.getComponentName());
 + });
 + }
 + ItemInstallQueue.INSTANCE.get(mApp.getContext())
 + .pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
 + newAppsMap.values().stream().forEach(item->{
 + ItemInstallQueue.INSTANCE.get(mApp.getContext())
 + .queueItem(item, item.getUser());
 + });
 + ItemInstallQueue.INSTANCE.get(mApp.getContext())
 + .resumeModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "updateForSingleLayerStyle end");
 + }
 + }
 +
 + private String getComponentKey(ComponentName componentName, int userId) {
 + return componentName.toString() + "_" + userId;
 + }
 +
     public synchronized void stopLocked() {
         mStopped = true;
         this.notify();
@@ -1053,6 + 1150,15 @@ public class LoaderTask implements Runnable {
                     info.suggestedFolderNames = suggestionInfos;
                 }
             }
 + if (DEBUG_BOBO) {
 + Log.d(TAG, "loadFolderNames mBgDataModel.folders size: " + mBgDataModel.folders.size());
 + for (int i = 0; i < mBgDataModel.folders.size(); i + + ) {
 + FolderInfo info = mBgDataModel.folders.valueAt(i);
 + Log.d(TAG, "info: " +
 + info.suggestedFolderNames);
 + }
 + Log.d(TAG, "loadFolderNames end");
 + }
         }
     }
 
diff --git a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
index 93fc6a539f..ec685f7902 100644
--- a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
 + + + b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java
@@ -66,7 + 66,7 @@ public class WorkspaceItemSpaceFinder {
         int screenCount = workspaceScreens.size();
         // First check the preferred screen.
         IntSet screensToExclude = new IntSet();
- if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
 + if (FeatureFlags.QSB_ON_FIRST_SCREEN || LauncherAppState.isUserSingleLayerStyle()) {
             screensToExclude.add(FIRST_SCREEN_ID);
         }
 
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 59ef320120..26299c91e9 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
 + + + b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -100,7 + 100,6 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
 
     public int options;
 
-
     public WorkspaceItemInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
     }
@@ -112,6 + 111,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
         iconResource = info.iconResource;
         status = info.status;
         personKeys = info.personKeys.clone();
 + mExtraFlags = info.mExtraFlags;
     }
 
     /** TODO: Remove this. It's only called by ApplicationInfo.makeWorkspaceItem. */
@@ -231,4 + 231,19 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
     public WorkspaceItemInfo clone() {
         return new WorkspaceItemInfo(this);
     }
 +
 +
 + public static final int EXTRA_FLAG_FORCE_ADD = 1;
 + private int mExtraFlags = 0;
 + public void addExtraFlag(int flag) {
 + mExtraFlags |= flag;
 + }
 +
 + public void removeExtraFlag(int flag) {
 + mExtraFlags & amp;= ~flag;
 + }
 +
 + public boolean hasExtraFlag(int flag) {
 + return (mExtraFlags & amp; flag) == flag;
 + }
 }
3. Delete the “remove” button of long-press the desktop icon
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 95d3ad9dbb..96b98e4667 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
 + + + b/src/com/android/launcher3/DeleteDropTarget.java
@@ -89,6 + 89,11 @@ public class DeleteDropTarget extends ButtonDropTarget {
 
     @Override
     protected boolean supportsDrop(ItemInfo info) {
 + if (info != null & amp; & amp;
 + info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
 + & amp; & amp; LauncherAppState.isUserSingleLayerStyle()) {
 + return false;
 + }
         return true;
     }