2016-09-09 15:47:55 -07:00
|
|
|
/*
|
|
|
|
|
* 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.Intent;
|
2019-08-19 13:32:09 -07:00
|
|
|
import android.content.pm.LauncherActivityInfo;
|
2019-10-02 16:13:34 -07:00
|
|
|
import android.content.pm.LauncherApps;
|
2019-08-19 13:32:09 -07:00
|
|
|
import android.content.pm.PackageInstaller.SessionInfo;
|
2016-12-15 15:53:17 -08:00
|
|
|
import android.os.UserHandle;
|
2016-09-09 15:47:55 -07:00
|
|
|
import android.util.Pair;
|
2018-12-07 11:43:47 -08:00
|
|
|
|
2022-09-16 09:44:26 -07:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
|
|
2016-09-09 15:47:55 -07:00
|
|
|
import com.android.launcher3.LauncherAppState;
|
|
|
|
|
import com.android.launcher3.LauncherModel.CallbackTask;
|
|
|
|
|
import com.android.launcher3.LauncherSettings;
|
2021-05-04 11:40:05 -07:00
|
|
|
import com.android.launcher3.logging.FileLog;
|
2019-09-20 12:51:37 -07:00
|
|
|
import com.android.launcher3.model.BgDataModel.Callbacks;
|
2020-04-06 15:11:17 -07:00
|
|
|
import com.android.launcher3.model.data.AppInfo;
|
|
|
|
|
import com.android.launcher3.model.data.FolderInfo;
|
|
|
|
|
import com.android.launcher3.model.data.ItemInfo;
|
2024-01-26 02:18:44 +05:30
|
|
|
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
2020-04-06 15:11:17 -07:00
|
|
|
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
2022-05-11 07:23:10 -07:00
|
|
|
import com.android.launcher3.model.data.WorkspaceItemFactory;
|
2020-04-06 15:11:17 -07:00
|
|
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
2019-12-09 14:55:56 -08:00
|
|
|
import com.android.launcher3.pm.InstallSessionHelper;
|
2021-01-12 19:30:02 +00:00
|
|
|
import com.android.launcher3.pm.PackageInstallInfo;
|
2018-10-04 15:11:00 -07:00
|
|
|
import com.android.launcher3.util.IntArray;
|
2019-07-17 15:12:56 -07:00
|
|
|
import com.android.launcher3.util.PackageManagerHelper;
|
2018-10-04 15:11:00 -07:00
|
|
|
|
2016-09-09 15:47:55 -07:00
|
|
|
import java.util.ArrayList;
|
2016-11-16 09:23:42 -08:00
|
|
|
import java.util.List;
|
2022-09-16 09:44:26 -07:00
|
|
|
import java.util.Objects;
|
2016-09-09 15:47:55 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Task to add auto-created workspace items.
|
|
|
|
|
*/
|
2017-06-06 14:33:18 -07:00
|
|
|
public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
|
2016-09-09 15:47:55 -07:00
|
|
|
|
2021-03-25 13:51:20 -07:00
|
|
|
private static final String LOG = "AddWorkspaceItemsTask";
|
|
|
|
|
|
2022-09-16 09:44:26 -07:00
|
|
|
@NonNull
|
2017-10-05 15:57:40 -07:00
|
|
|
private final List<Pair<ItemInfo, Object>> mItemList;
|
2016-09-09 15:47:55 -07:00
|
|
|
|
2022-09-16 09:44:26 -07:00
|
|
|
@NonNull
|
2021-11-22 16:54:54 +00:00
|
|
|
private final WorkspaceItemSpaceFinder mItemSpaceFinder;
|
|
|
|
|
|
2016-09-09 15:47:55 -07:00
|
|
|
/**
|
2017-10-05 15:57:40 -07:00
|
|
|
* @param itemList items to add on the workspace
|
2016-09-09 15:47:55 -07:00
|
|
|
*/
|
2022-09-16 09:44:26 -07:00
|
|
|
public AddWorkspaceItemsTask(@NonNull final List<Pair<ItemInfo, Object>> itemList) {
|
2021-11-22 16:54:54 +00:00
|
|
|
this(itemList, new WorkspaceItemSpaceFinder());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param itemList items to add on the workspace
|
|
|
|
|
* @param itemSpaceFinder inject WorkspaceItemSpaceFinder dependency for testing
|
|
|
|
|
*/
|
2022-09-16 09:44:26 -07:00
|
|
|
public AddWorkspaceItemsTask(@NonNull final List<Pair<ItemInfo, Object>> itemList,
|
|
|
|
|
@NonNull final WorkspaceItemSpaceFinder itemSpaceFinder) {
|
2017-10-05 15:57:40 -07:00
|
|
|
mItemList = itemList;
|
2021-11-22 16:54:54 +00:00
|
|
|
mItemSpaceFinder = itemSpaceFinder;
|
2016-09-09 15:47:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-09-16 09:44:26 -07:00
|
|
|
public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
|
|
|
|
|
@NonNull final AllAppsList apps) {
|
2017-10-05 15:57:40 -07:00
|
|
|
if (mItemList.isEmpty()) {
|
2016-09-09 15:47:55 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 09:59:25 -08:00
|
|
|
final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
|
2018-10-04 15:11:00 -07:00
|
|
|
final IntArray addedWorkspaceScreensFinal = new IntArray();
|
2016-09-09 15:47:55 -07:00
|
|
|
|
2021-11-22 16:54:54 +00:00
|
|
|
synchronized (dataModel) {
|
2018-12-27 13:58:25 -08:00
|
|
|
IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
|
2017-05-04 16:47:11 -07:00
|
|
|
|
|
|
|
|
List<ItemInfo> filteredItems = new ArrayList<>();
|
2017-10-05 15:57:40 -07:00
|
|
|
for (Pair<ItemInfo, Object> entry : mItemList) {
|
2017-05-04 16:47:11 -07:00
|
|
|
ItemInfo item = entry.first;
|
2023-05-01 16:55:59 -07:00
|
|
|
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
|
2016-09-09 15:47:55 -07:00
|
|
|
// Short-circuit this logic if the icon exists somewhere on the workspace
|
|
|
|
|
if (shortcutExists(dataModel, item.getIntent(), item.user)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-10-30 09:56:44 -07:00
|
|
|
|
|
|
|
|
// b/139663018 Short-circuit this logic if the icon is a system app
|
2022-09-16 09:44:26 -07:00
|
|
|
if (PackageManagerHelper.isSystemApp(app.getContext(),
|
|
|
|
|
Objects.requireNonNull(item.getIntent()))) {
|
2019-10-30 09:56:44 -07:00
|
|
|
continue;
|
|
|
|
|
}
|
2024-01-26 02:18:44 +05:30
|
|
|
|
|
|
|
|
if (item instanceof ItemInfoWithIcon
|
|
|
|
|
&& ((ItemInfoWithIcon) item).isArchived()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2016-09-09 15:47:55 -07:00
|
|
|
}
|
|
|
|
|
|
2017-05-04 16:47:11 -07:00
|
|
|
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
|
2022-05-11 07:23:10 -07:00
|
|
|
if (item instanceof WorkspaceItemFactory) {
|
|
|
|
|
item = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
|
2017-05-04 16:47:11 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (item != null) {
|
|
|
|
|
filteredItems.add(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-09 14:55:56 -08:00
|
|
|
InstallSessionHelper packageInstaller =
|
|
|
|
|
InstallSessionHelper.INSTANCE.get(app.getContext());
|
2019-10-02 16:13:34 -07:00
|
|
|
LauncherApps launcherApps = app.getContext().getSystemService(LauncherApps.class);
|
2019-08-19 13:32:09 -07:00
|
|
|
|
2017-05-04 16:47:11 -07:00
|
|
|
for (ItemInfo item : filteredItems) {
|
2016-09-09 15:47:55 -07:00
|
|
|
// Find appropriate space for the item.
|
2021-11-22 16:54:54 +00:00
|
|
|
int[] coords = mItemSpaceFinder.findSpaceForItem(app, dataModel, workspaceScreens,
|
2016-12-08 09:59:25 -08:00
|
|
|
addedWorkspaceScreensFinal, item.spanX, item.spanY);
|
2018-10-04 15:11:00 -07:00
|
|
|
int screenId = coords[0];
|
2016-09-09 15:47:55 -07:00
|
|
|
|
|
|
|
|
ItemInfo itemInfo;
|
2019-03-27 16:03:06 -07:00
|
|
|
if (item instanceof WorkspaceItemInfo || item instanceof FolderInfo ||
|
2016-12-08 09:59:25 -08:00
|
|
|
item instanceof LauncherAppWidgetInfo) {
|
2016-09-09 15:47:55 -07:00
|
|
|
itemInfo = item;
|
2022-05-11 07:23:10 -07:00
|
|
|
} else if (item instanceof WorkspaceItemFactory) {
|
|
|
|
|
itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
|
2016-09-09 15:47:55 -07:00
|
|
|
} else {
|
|
|
|
|
throw new RuntimeException("Unexpected info type");
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-19 13:32:09 -07:00
|
|
|
if (item instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) item).isPromise()) {
|
|
|
|
|
WorkspaceItemInfo workspaceInfo = (WorkspaceItemInfo) item;
|
|
|
|
|
String packageName = item.getTargetComponent() != null
|
|
|
|
|
? item.getTargetComponent().getPackageName() : null;
|
|
|
|
|
if (packageName == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
SessionInfo sessionInfo = packageInstaller.getActiveSessionInfo(item.user,
|
|
|
|
|
packageName);
|
2021-04-19 17:02:23 -07:00
|
|
|
|
|
|
|
|
if (!packageInstaller.verifySessionInfo(sessionInfo)) {
|
2021-06-01 14:43:14 -07:00
|
|
|
FileLog.d(LOG, "Item info failed session info verification. "
|
|
|
|
|
+ "Skipping : " + workspaceInfo);
|
|
|
|
|
continue;
|
2021-04-19 17:02:23 -07:00
|
|
|
}
|
|
|
|
|
|
2022-09-16 09:44:26 -07:00
|
|
|
List<LauncherActivityInfo> activities = Objects.requireNonNull(launcherApps)
|
2019-10-24 13:27:11 -07:00
|
|
|
.getActivityList(packageName, item.user);
|
|
|
|
|
boolean hasActivity = activities != null && !activities.isEmpty();
|
|
|
|
|
|
2019-08-19 13:32:09 -07:00
|
|
|
if (sessionInfo == null) {
|
2019-10-24 13:27:11 -07:00
|
|
|
if (!hasActivity) {
|
2019-08-19 13:32:09 -07:00
|
|
|
// Session was cancelled, do not add.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-01-12 19:30:02 +00:00
|
|
|
workspaceInfo.setProgressLevel(
|
|
|
|
|
(int) (sessionInfo.getProgress() * 100),
|
|
|
|
|
PackageInstallInfo.STATUS_INSTALLING);
|
2019-08-19 13:32:09 -07:00
|
|
|
}
|
2019-10-24 13:27:11 -07:00
|
|
|
|
|
|
|
|
if (hasActivity) {
|
|
|
|
|
// App was installed while launcher was in the background,
|
|
|
|
|
// or app was already installed for another user.
|
|
|
|
|
itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user)
|
2022-05-11 07:23:10 -07:00
|
|
|
.makeWorkspaceItem(app.getContext());
|
2019-11-04 14:19:17 -08:00
|
|
|
|
|
|
|
|
if (shortcutExists(dataModel, itemInfo.getIntent(), itemInfo.user)) {
|
|
|
|
|
// We need this additional check here since we treat all auto added
|
|
|
|
|
// workspace items as promise icons. At this point we now have the
|
|
|
|
|
// correct intent to compare against existing workspace icons.
|
|
|
|
|
// Icon already exists on the workspace and should not be auto-added.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:27:11 -07:00
|
|
|
WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
|
|
|
|
|
wii.title = "";
|
2019-10-25 13:41:28 -07:00
|
|
|
wii.bitmap = app.getIconCache().getDefaultIcon(item.user);
|
2019-10-24 13:27:11 -07:00
|
|
|
app.getIconCache().getTitleAndIcon(wii,
|
|
|
|
|
((WorkspaceItemInfo) itemInfo).usingLowResIcon());
|
|
|
|
|
}
|
2019-08-19 13:32:09 -07:00
|
|
|
}
|
|
|
|
|
|
2016-09-09 15:47:55 -07:00
|
|
|
// Add the shortcut to the db
|
2017-02-02 13:52:53 -08:00
|
|
|
getModelWriter().addItemToDatabase(itemInfo,
|
|
|
|
|
LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,
|
2018-10-04 15:11:00 -07:00
|
|
|
coords[1], coords[2]);
|
2016-09-09 15:47:55 -07:00
|
|
|
|
2019-03-27 16:03:06 -07:00
|
|
|
// Save the WorkspaceItemInfo for binding in the workspace
|
2016-12-08 09:59:25 -08:00
|
|
|
addedItemsFinal.add(itemInfo);
|
2021-03-25 13:51:20 -07:00
|
|
|
|
2021-04-19 17:02:23 -07:00
|
|
|
// log bitmap and label
|
2021-05-04 11:40:05 -07:00
|
|
|
FileLog.d(LOG, "Adding item info to workspace: " + itemInfo);
|
2016-09-09 15:47:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 09:59:25 -08:00
|
|
|
if (!addedItemsFinal.isEmpty()) {
|
2016-09-09 15:47:55 -07:00
|
|
|
scheduleCallbackTask(new CallbackTask() {
|
|
|
|
|
@Override
|
2022-09-16 09:44:26 -07:00
|
|
|
public void execute(@NonNull Callbacks callbacks) {
|
2017-06-14 17:50:51 -07:00
|
|
|
final ArrayList<ItemInfo> addAnimated = new ArrayList<>();
|
|
|
|
|
final ArrayList<ItemInfo> addNotAnimated = new ArrayList<>();
|
2016-12-08 09:59:25 -08:00
|
|
|
if (!addedItemsFinal.isEmpty()) {
|
|
|
|
|
ItemInfo info = addedItemsFinal.get(addedItemsFinal.size() - 1);
|
2018-10-04 15:11:00 -07:00
|
|
|
int lastScreenId = info.screenId;
|
2016-12-08 09:59:25 -08:00
|
|
|
for (ItemInfo i : addedItemsFinal) {
|
2016-09-09 15:47:55 -07:00
|
|
|
if (i.screenId == lastScreenId) {
|
|
|
|
|
addAnimated.add(i);
|
|
|
|
|
} else {
|
|
|
|
|
addNotAnimated.add(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
callbacks.bindAppsAdded(addedWorkspaceScreensFinal,
|
2017-08-17 07:45:25 -07:00
|
|
|
addNotAnimated, addAnimated);
|
2016-09-09 15:47:55 -07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2022-09-16 09:44:26 -07:00
|
|
|
protected boolean shortcutExists(@NonNull final BgDataModel dataModel,
|
|
|
|
|
@Nullable final Intent intent, @NonNull final UserHandle user) {
|
2017-03-21 15:49:06 -07:00
|
|
|
final String compPkgName, intentWithPkg, intentWithoutPkg;
|
2017-01-13 12:15:53 -08:00
|
|
|
if (intent == null) {
|
|
|
|
|
// Skip items with null intents
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-09-09 15:47:55 -07:00
|
|
|
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.
|
2017-03-21 15:49:06 -07:00
|
|
|
compPkgName = intent.getComponent().getPackageName();
|
2016-09-09 15:47:55 -07:00
|
|
|
if (intent.getPackage() != null) {
|
|
|
|
|
intentWithPkg = intent.toUri(0);
|
|
|
|
|
intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);
|
|
|
|
|
} else {
|
2017-03-21 15:49:06 -07:00
|
|
|
intentWithPkg = new Intent(intent).setPackage(compPkgName).toUri(0);
|
2016-09-09 15:47:55 -07:00
|
|
|
intentWithoutPkg = intent.toUri(0);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2017-03-21 15:49:06 -07:00
|
|
|
compPkgName = null;
|
2016-09-09 15:47:55 -07:00
|
|
|
intentWithPkg = intent.toUri(0);
|
|
|
|
|
intentWithoutPkg = intent.toUri(0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-17 15:12:56 -07:00
|
|
|
boolean isLauncherAppTarget = PackageManagerHelper.isLauncherAppTarget(intent);
|
2016-09-09 15:47:55 -07:00
|
|
|
synchronized (dataModel) {
|
|
|
|
|
for (ItemInfo item : dataModel.itemsIdMap) {
|
2019-03-27 16:03:06 -07:00
|
|
|
if (item instanceof WorkspaceItemInfo) {
|
|
|
|
|
WorkspaceItemInfo info = (WorkspaceItemInfo) item;
|
2017-01-12 16:55:36 -08:00
|
|
|
if (item.getIntent() != null && info.user.equals(user)) {
|
|
|
|
|
Intent copyIntent = new Intent(item.getIntent());
|
2016-09-09 15:47:55 -07:00
|
|
|
copyIntent.setSourceBounds(intent.getSourceBounds());
|
|
|
|
|
String s = copyIntent.toUri(0);
|
|
|
|
|
if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-03-21 15:49:06 -07:00
|
|
|
|
|
|
|
|
// checking for existing promise icon with same package name
|
|
|
|
|
if (isLauncherAppTarget
|
|
|
|
|
&& info.isPromise()
|
2019-03-27 16:03:06 -07:00
|
|
|
&& info.hasStatusFlag(WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON)
|
2017-03-21 15:49:06 -07:00
|
|
|
&& info.getTargetComponent() != null
|
|
|
|
|
&& compPkgName != null
|
|
|
|
|
&& compPkgName.equals(info.getTargetComponent().getPackageName())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-09-09 15:47:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|