summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2016-09-09 15:47:55 -0700
committerSunny Goyal <sunnygoyal@google.com>2016-11-09 15:50:08 -0800
commitf0ba8b7ca1dc8fd53451d3d16e9f4fc306cddcd4 (patch)
tree821627bf354c858215e48c58cc5122a94ebd9c08 /src/com/android/launcher3/model/AddWorkspaceItemsTask.java
parent0d547bfd570e2e5d6ced55e24305d070fe2b78e2 (diff)
downloadandroid_packages_apps_Trebuchet-f0ba8b7ca1dc8fd53451d3d16e9f4fc306cddcd4.tar.gz
android_packages_apps_Trebuchet-f0ba8b7ca1dc8fd53451d3d16e9f4fc306cddcd4.tar.bz2
android_packages_apps_Trebuchet-f0ba8b7ca1dc8fd53451d3d16e9f4fc306cddcd4.zip
Moving various runnables in LauncherModel to individual tasks
> Adding tests for some of the runnable Change-Id: I1a315d38878857df3371f0e69d622a41fc3b081a
Diffstat (limited to 'src/com/android/launcher3/model/AddWorkspaceItemsTask.java')
-rw-r--r--src/com/android/launcher3/model/AddWorkspaceItemsTask.java262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
new file mode 100644
index 000000000..986e163e6
--- /dev/null
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.LongSparseArray;
+import android.util.Pair;
+
+import com.android.launcher3.AllAppsList;
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherModel.CallbackTask;
+import com.android.launcher3.LauncherModel.Callbacks;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.GridOccupancy;
+
+import java.util.ArrayList;
+
+/**
+ * Task to add auto-created workspace items.
+ */
+public class AddWorkspaceItemsTask extends ExtendedModelTask {
+
+ private final ArrayList<? extends ItemInfo> mWorkspaceApps;
+
+ /**
+ * @param workspaceApps items to add on the workspace
+ */
+ public AddWorkspaceItemsTask(ArrayList<? extends ItemInfo> workspaceApps) {
+ mWorkspaceApps = workspaceApps;
+ }
+
+ @Override
+ public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
+ if (mWorkspaceApps.isEmpty()) {
+ return;
+ }
+ Context context = app.getContext();
+
+ final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();
+ final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
+
+ // Get the list of workspace screens. We need to append to this list and
+ // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
+ // called.
+ ArrayList<Long> workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
+ synchronized(dataModel) {
+ for (ItemInfo item : mWorkspaceApps) {
+ if (item instanceof ShortcutInfo) {
+ // Short-circuit this logic if the icon exists somewhere on the workspace
+ if (shortcutExists(dataModel, item.getIntent(), item.user)) {
+ continue;
+ }
+ }
+
+ // Find appropriate space for the item.
+ Pair<Long, int[]> coords = findSpaceForItem(
+ app, dataModel, workspaceScreens, addedWorkspaceScreensFinal, 1, 1);
+ long screenId = coords.first;
+ int[] cordinates = coords.second;
+
+ ItemInfo itemInfo;
+ if (item instanceof ShortcutInfo || item instanceof FolderInfo) {
+ itemInfo = item;
+ } else if (item instanceof AppInfo) {
+ itemInfo = ((AppInfo) item).makeShortcut();
+ } else {
+ throw new RuntimeException("Unexpected info type");
+ }
+
+ // Add the shortcut to the db
+ addItemToDatabase(context, itemInfo, screenId, cordinates);
+
+ // Save the ShortcutInfo for binding in the workspace
+ addedShortcutsFinal.add(itemInfo);
+ }
+ }
+
+ // Update the workspace screens
+ updateScreens(context, workspaceScreens);
+
+ if (!addedShortcutsFinal.isEmpty()) {
+ scheduleCallbackTask(new CallbackTask() {
+ @Override
+ public void execute(Callbacks callbacks) {
+ final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();
+ final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();
+ if (!addedShortcutsFinal.isEmpty()) {
+ ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);
+ long lastScreenId = info.screenId;
+ for (ItemInfo i : addedShortcutsFinal) {
+ if (i.screenId == lastScreenId) {
+ addAnimated.add(i);
+ } else {
+ addNotAnimated.add(i);
+ }
+ }
+ }
+ callbacks.bindAppsAdded(addedWorkspaceScreensFinal,
+ addNotAnimated, addAnimated, null);
+ }
+ });
+ }
+ }
+
+ protected void addItemToDatabase(Context context, ItemInfo item, long screenId, int[] pos) {
+ LauncherModel.addItemToDatabase(context, item,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, pos[0], pos[1]);
+ }
+
+ protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) {
+ LauncherModel.updateWorkspaceScreenOrder(context, workspaceScreens);
+ }
+
+ /**
+ * Returns true if the shortcuts already exists on the workspace. This must be called after
+ * the workspace has been loaded. We identify a shortcut by its intent.
+ */
+ protected boolean shortcutExists(BgDataModel dataModel, Intent intent, UserHandleCompat user) {
+ final String intentWithPkg, intentWithoutPkg;
+ if (intent.getComponent() != null) {
+ // If component is not null, an intent with null package will produce
+ // the same result and should also be a match.
+ String packageName = intent.getComponent().getPackageName();
+ if (intent.getPackage() != null) {
+ intentWithPkg = intent.toUri(0);
+ intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);
+ } else {
+ intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);
+ intentWithoutPkg = intent.toUri(0);
+ }
+ } else {
+ intentWithPkg = intent.toUri(0);
+ intentWithoutPkg = intent.toUri(0);
+ }
+
+ synchronized (dataModel) {
+ for (ItemInfo item : dataModel.itemsIdMap) {
+ if (item instanceof ShortcutInfo) {
+ ShortcutInfo info = (ShortcutInfo) item;
+ Intent targetIntent = info.promisedIntent == null
+ ? info.intent : info.promisedIntent;
+ if (targetIntent != null && info.user.equals(user)) {
+ Intent copyIntent = new Intent(targetIntent);
+ copyIntent.setSourceBounds(intent.getSourceBounds());
+ String s = copyIntent.toUri(0);
+ if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Find a position on the screen for the given size or adds a new screen.
+ * @return screenId and the coordinates for the item.
+ */
+ protected Pair<Long, int[]> findSpaceForItem(
+ LauncherAppState app, BgDataModel dataModel,
+ ArrayList<Long> workspaceScreens,
+ ArrayList<Long> addedWorkspaceScreensFinal,
+ int spanX, int spanY) {
+ LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();
+
+ // Use sBgItemsIdMap as all the items are already loaded.
+ synchronized (dataModel) {
+ for (ItemInfo info : dataModel.itemsIdMap) {
+ if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ ArrayList<ItemInfo> items = screenItems.get(info.screenId);
+ if (items == null) {
+ items = new ArrayList<>();
+ screenItems.put(info.screenId, items);
+ }
+ items.add(info);
+ }
+ }
+ }
+
+ // Find appropriate space for the item.
+ long 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;
+ if (preferredScreenIndex < screenCount) {
+ screenId = workspaceScreens.get(preferredScreenIndex);
+ found = findNextAvailableIconSpaceInScreen(
+ app, screenItems.get(screenId), cordinates, spanX, spanY);
+ }
+
+ if (!found) {
+ // Search on any of the screens starting from the first screen.
+ for (int screen = 1; screen < screenCount; screen++) {
+ screenId = workspaceScreens.get(screen);
+ if (findNextAvailableIconSpaceInScreen(
+ app, screenItems.get(screenId), cordinates, spanX, spanY)) {
+ // We found a space for it
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ // Still no position found. Add a new screen to the end.
+ screenId = LauncherSettings.Settings.call(app.getContext().getContentResolver(),
+ LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
+ .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+
+ // Save the screen id for binding in the workspace
+ workspaceScreens.add(screenId);
+ addedWorkspaceScreensFinal.add(screenId);
+
+ // If we still can't find an empty space, then God help us all!!!
+ if (!findNextAvailableIconSpaceInScreen(
+ app, screenItems.get(screenId), cordinates, spanX, spanY)) {
+ throw new RuntimeException("Can't find space to add the item");
+ }
+ }
+ return Pair.create(screenId, cordinates);
+ }
+
+ private boolean findNextAvailableIconSpaceInScreen(
+ LauncherAppState app, ArrayList<ItemInfo> occupiedPos,
+ int[] xy, int spanX, int spanY) {
+ InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+
+ GridOccupancy occupied = new GridOccupancy(profile.numColumns, profile.numRows);
+ if (occupiedPos != null) {
+ for (ItemInfo r : occupiedPos) {
+ occupied.markCells(r, true);
+ }
+ }
+ return occupied.findVacantCell(xy, spanX, spanY);
+ }
+
+}