Merge "App Pairs (behind flag): Add new ItemInfo types and DB save functionality" into udc-dev
This commit is contained in:
@@ -128,19 +128,19 @@ public interface TaskShortcutFactory {
|
||||
* A menu item, "Save app pair", that allows the user to preserve the current app combination as
|
||||
* a single persistent icon on the Home screen, allowing for quick split screen initialization.
|
||||
*/
|
||||
class SaveAppPairSystemShortcut extends SystemShortcut {
|
||||
|
||||
class SaveAppPairSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
|
||||
private final TaskView mTaskView;
|
||||
|
||||
public SaveAppPairSystemShortcut(BaseDraggingActivity target, TaskView taskView) {
|
||||
super(R.drawable.ic_save_app_pair, R.string.save_app_pair, target,
|
||||
public SaveAppPairSystemShortcut(BaseDraggingActivity activity, TaskView taskView) {
|
||||
super(R.drawable.ic_save_app_pair, R.string.save_app_pair, activity,
|
||||
taskView.getItemInfo(), taskView);
|
||||
mTaskView = taskView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// TODO (b/274189428): Call "saveAppPair" function in new AppPairController class
|
||||
((RecentsView) mTarget.getOverviewPanel())
|
||||
.getSplitSelectController().getAppPairsController().saveAppPair(mTaskView);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2023 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.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
|
||||
/**
|
||||
* Mini controller class that handles app pair interactions: saving, modifying, deleting, etc.
|
||||
*/
|
||||
public class AppPairsController {
|
||||
|
||||
private static final int POINT_THREE_RATIO = 0;
|
||||
private static final int POINT_FIVE_RATIO = 1;
|
||||
private static final int POINT_SEVEN_RATIO = 2;
|
||||
/**
|
||||
* Used to calculate {@link #complement(int)}
|
||||
*/
|
||||
private static final int FULL_RATIO = 2;
|
||||
|
||||
private static final int LEFT_TOP = 0;
|
||||
private static final int RIGHT_BOTTOM = 1 << 2;
|
||||
|
||||
// TODO (jeremysim b/274189428): Support saving different ratios in future.
|
||||
public int DEFAULT_RATIO = POINT_FIVE_RATIO;
|
||||
|
||||
private final Context mContext;
|
||||
private final SplitSelectStateController mSplitSelectStateController;
|
||||
public AppPairsController(Context context,
|
||||
SplitSelectStateController splitSelectStateController) {
|
||||
mContext = context;
|
||||
mSplitSelectStateController = splitSelectStateController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new app pair ItemInfo and adds it to the workspace
|
||||
*/
|
||||
public void saveAppPair(TaskView taskView) {
|
||||
TaskView.TaskIdAttributeContainer[] attributes = taskView.getTaskIdAttributeContainers();
|
||||
WorkspaceItemInfo app1 = attributes[0].getItemInfo().clone();
|
||||
WorkspaceItemInfo app2 = attributes[1].getItemInfo().clone();
|
||||
app1.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
app2.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
app1.rank = DEFAULT_RATIO + LEFT_TOP;
|
||||
app2.rank = complement(DEFAULT_RATIO) + RIGHT_BOTTOM;
|
||||
FolderInfo newAppPair = FolderInfo.createAppPair(app1, app2);
|
||||
// TODO (jeremysim b/274189428): Generate default title here.
|
||||
newAppPair.title = "App pair 1";
|
||||
|
||||
IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache();
|
||||
MODEL_EXECUTOR.execute(() -> {
|
||||
newAppPair.contents.forEach(member -> {
|
||||
member.title = "";
|
||||
member.bitmap = iconCache.getDefaultIcon(newAppPair.user);
|
||||
iconCache.getTitleAndIcon(member, member.usingLowResIcon());
|
||||
});
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
LauncherAccessibilityDelegate delegate =
|
||||
Launcher.getLauncher(mContext).getAccessibilityDelegate();
|
||||
if (delegate != null) {
|
||||
MAIN_EXECUTOR.execute(() -> delegate.addToWorkspace(newAppPair, true));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to calculate the "opposite" side of the split ratio, so we can know how big the split
|
||||
* apps are supposed to be. This math works because POINT_THREE_RATIO is internally represented
|
||||
* by 0, POINT_FIVE_RATIO is represented by 1, and POINT_SEVEN_RATIO is represented by 2. There
|
||||
* are no other supported ratios for now.
|
||||
*/
|
||||
private int complement(int ratio1) {
|
||||
int ratio2 = FULL_RATIO - ratio1;
|
||||
return ratio2;
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,7 @@ public class SplitSelectStateController {
|
||||
private final Handler mHandler;
|
||||
private final RecentsModel mRecentTasksModel;
|
||||
private final SplitAnimationController mSplitAnimationController;
|
||||
private final AppPairsController mAppPairsController;
|
||||
private StatsLogManager mStatsLogManager;
|
||||
private final SystemUiProxy mSystemUiProxy;
|
||||
private final StateManager mStateManager;
|
||||
@@ -128,6 +129,7 @@ public class SplitSelectStateController {
|
||||
mDepthController = depthController;
|
||||
mRecentTasksModel = recentsModel;
|
||||
mSplitAnimationController = new SplitAnimationController(this);
|
||||
mAppPairsController = new AppPairsController(context, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,4 +589,8 @@ public class SplitSelectStateController {
|
||||
public FloatingTaskView getFirstFloatingTaskView() {
|
||||
return mFirstFloatingTaskView;
|
||||
}
|
||||
|
||||
public AppPairsController getAppPairsController() {
|
||||
return mAppPairsController;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ import static com.android.launcher3.popup.SystemShortcut.INSTALL;
|
||||
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
|
||||
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
|
||||
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -2414,6 +2416,12 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
(FolderInfo) item);
|
||||
break;
|
||||
}
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR: {
|
||||
FolderInfo info = (FolderInfo) item;
|
||||
// TODO (jeremysim b/274189428): Create app pair icon
|
||||
view = null;
|
||||
break;
|
||||
}
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
|
||||
view = inflateAppWidget((LauncherAppWidgetInfo) item);
|
||||
|
||||
@@ -112,6 +112,10 @@ public class LauncherSettings {
|
||||
*/
|
||||
public static final int ITEM_TYPE_DEEP_SHORTCUT = 6;
|
||||
|
||||
/**
|
||||
* The favorite is an app pair for launching split screen
|
||||
*/
|
||||
public static final int ITEM_TYPE_APP_PAIR = 10;
|
||||
|
||||
// *** Below enum values are used for metrics purpose but not used in Favorites DB ***
|
||||
|
||||
@@ -233,6 +237,7 @@ public class LauncherSettings {
|
||||
case ITEM_TYPE_DEEP_SHORTCUT: return "DEEPSHORTCUT";
|
||||
case ITEM_TYPE_TASK: return "TASK";
|
||||
case ITEM_TYPE_QSB: return "QSB";
|
||||
case ITEM_TYPE_APP_PAIR: return "APP_PAIR";
|
||||
default: return String.valueOf(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,6 +408,14 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP,
|
||||
screenId, coordinates[0], coordinates[1]);
|
||||
mContext.bindItems(Collections.singletonList(info), true, accessibility);
|
||||
} else if (item instanceof FolderInfo fi) {
|
||||
mContext.getModelWriter().addItemToDatabase(fi,
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0],
|
||||
coordinates[1]);
|
||||
fi.contents.forEach(member -> {
|
||||
mContext.getModelWriter().addItemToDatabase(member, fi.id, -1, -1, -1);
|
||||
});
|
||||
mContext.bindItems(Collections.singletonList(fi), true, accessibility);
|
||||
}
|
||||
}));
|
||||
return true;
|
||||
|
||||
@@ -190,14 +190,15 @@ public class BgDataModel {
|
||||
for (ItemInfo item : items) {
|
||||
switch (item.itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
|
||||
folders.remove(item.id);
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
for (ItemInfo info : itemsIdMap) {
|
||||
if (info.container == item.id) {
|
||||
// We are deleting a folder which still contains items that
|
||||
// think they are contained by that folder.
|
||||
String msg = "deleting a folder (" + item + ") which still " +
|
||||
"contains items (" + info + ")";
|
||||
String msg = "deleting a collection (" + item + ") which still "
|
||||
+ "contains items (" + info + ")";
|
||||
Log.e(TAG, msg);
|
||||
}
|
||||
}
|
||||
@@ -238,6 +239,7 @@ public class BgDataModel {
|
||||
itemsIdMap.put(item.id, item);
|
||||
switch (item.itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
|
||||
folders.put(item.id, (FolderInfo) item);
|
||||
workspaceItems.add(item);
|
||||
break;
|
||||
@@ -250,15 +252,14 @@ public class BgDataModel {
|
||||
} else {
|
||||
if (newItem) {
|
||||
if (!folders.containsKey(item.container)) {
|
||||
// Adding an item to a folder that doesn't exist.
|
||||
String msg = "adding item: " + item + " to a folder that " +
|
||||
" doesn't exist";
|
||||
// Adding an item to a nonexistent collection.
|
||||
String msg = "attempted to add item: " + item + " to a nonexistent app"
|
||||
+ " collection";
|
||||
Log.e(TAG, msg);
|
||||
}
|
||||
} else {
|
||||
findOrMakeFolder(item.container).add((WorkspaceItemInfo) item, false);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
|
||||
|
||||
@@ -113,6 +113,17 @@ public class FolderInfo extends ItemInfo {
|
||||
user = Process.myUserHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an app pair, a type of app collection that launches multiple apps into split screen
|
||||
*/
|
||||
public static FolderInfo createAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
|
||||
FolderInfo newAppPair = new FolderInfo();
|
||||
newAppPair.itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
|
||||
newAppPair.contents.add(app1);
|
||||
newAppPair.contents.add(app2);
|
||||
return newAppPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an app or shortcut
|
||||
*
|
||||
|
||||
@@ -90,6 +90,7 @@ public class ItemInfo {
|
||||
* {@link Favorites#ITEM_TYPE_SHORTCUT},
|
||||
* {@link Favorites#ITEM_TYPE_DEEP_SHORTCUT}
|
||||
* {@link Favorites#ITEM_TYPE_FOLDER},
|
||||
* {@link Favorites#ITEM_TYPE_APP_PAIR},
|
||||
* {@link Favorites#ITEM_TYPE_APPWIDGET} or
|
||||
* {@link Favorites#ITEM_TYPE_CUSTOM_APPWIDGET}.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user