diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2016-09-09 15:47:55 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2016-11-09 15:50:08 -0800 |
commit | f0ba8b7ca1dc8fd53451d3d16e9f4fc306cddcd4 (patch) | |
tree | 821627bf354c858215e48c58cc5122a94ebd9c08 /src/com/android/launcher3/model/AddWorkspaceItemsTask.java | |
parent | 0d547bfd570e2e5d6ced55e24305d070fe2b78e2 (diff) | |
download | android_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.java | 262 |
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); + } + +} |