diff options
Diffstat (limited to 'quickstep/src')
4 files changed, 184 insertions, 84 deletions
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java index 080633a653..56945ba0a6 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java @@ -16,33 +16,25 @@ package com.android.launcher3.hybridhotseat; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; +import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo; +import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction; +import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; -import android.app.prediction.AppTargetId; -import android.content.ComponentName; import android.content.Context; import android.os.Bundle; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.Workspace; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.shortcuts.ShortcutKey; import java.util.ArrayList; -import java.util.Locale; /** * Model helper for app predictions in workspace */ public class HotseatPredictionModel { - private static final String APP_LOCATION_HOTSEAT = "hotseat"; - private static final String APP_LOCATION_WORKSPACE = "workspace"; - private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events"; private static final String BUNDLE_KEY_CURRENT_ITEMS = "current_items"; @@ -54,15 +46,15 @@ public class HotseatPredictionModel { ArrayList<AppTargetEvent> events = new ArrayList<>(); ArrayList<ItemInfo> workspaceItems = dataModel.getAllWorkspaceItems(); for (ItemInfo item : workspaceItems) { - AppTarget target = getAppTargetFromInfo(context, item); - if (target != null && !isTrackedForPrediction(item)) continue; - events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item)); + AppTarget target = getAppTargetFromItemInfo(context, item); + if (target != null && !isTrackedForHotseatPrediction(item)) continue; + events.add(wrapAppTargetWithItemLocation(target, AppTargetEvent.ACTION_PIN, item)); } ArrayList<AppTarget> currentTargets = new ArrayList<>(); FixedContainerItems hotseatItems = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION); if (hotseatItems != null) { for (ItemInfo itemInfo : hotseatItems.items) { - AppTarget target = getAppTargetFromInfo(context, itemInfo); + AppTarget target = getAppTargetFromItemInfo(context, itemInfo); if (target != null) currentTargets.add(target); } } @@ -70,56 +62,4 @@ public class HotseatPredictionModel { bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets); return bundle; } - - /** - * Creates and returns for {@link AppTarget} object given an {@link ItemInfo}. Returns null - * if item is not supported prediction - */ - public static AppTarget getAppTargetFromInfo(Context context, ItemInfo info) { - if (info == null) return null; - if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET - && info instanceof LauncherAppWidgetInfo - && ((LauncherAppWidgetInfo) info).providerName != null) { - ComponentName cn = ((LauncherAppWidgetInfo) info).providerName; - return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()), - cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); - } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION - && info.getTargetComponent() != null) { - ComponentName cn = info.getTargetComponent(); - return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), - cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); - } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT - && info instanceof WorkspaceItemInfo) { - ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info); - //TODO: switch to using full shortcut info - return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()), - shortcutKey.componentName.getPackageName(), shortcutKey.user).build(); - } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { - return new AppTarget.Builder(new AppTargetId("folder:" + info.id), - context.getPackageName(), info.user).build(); - } - return null; - } - - /** - * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item - * location using {@link ItemInfo} - */ - public static AppTargetEvent wrapAppTargetWithLocation( - AppTarget target, int action, ItemInfo info) { - String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]", - info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT - ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE, - info.screenId, info.cellX, info.cellY, info.spanX, info.spanY); - return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build(); - } - - /** - * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors - */ - public static boolean isTrackedForPrediction(ItemInfo info) { - return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || ( - info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP - && info.screenId == Workspace.FIRST_SCREEN_ID); - } } diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java index b665db6ffc..09233a4e17 100644 --- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java +++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java @@ -22,6 +22,7 @@ import static android.app.prediction.AppTargetEvent.ACTION_UNPIN; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED; @@ -35,6 +36,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP; +import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction; +import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.annotation.TargetApi; @@ -62,7 +65,6 @@ import com.android.launcher3.logger.LauncherAtom.FolderContainer; import com.android.launcher3.logger.LauncherAtom.HotseatContainer; import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer; import com.android.launcher3.logging.StatsLogManager.EventEnum; -import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer; @@ -141,6 +143,9 @@ public class AppEventProducer implements StatsLogConsumer { if (isTrackedForHotseatPrediction(mLastDragItem)) { sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); } + if (isTrackedForWidgetPrediction(atomInfo)) { + sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION); + } mLastDragItem = null; } else if (event == LAUNCHER_ITEM_DROP_FOLDER_CREATED) { if (isTrackedForHotseatPrediction(atomInfo)) { @@ -158,6 +163,9 @@ public class AppEventProducer implements StatsLogConsumer { if (mLastDragItem != null && isTrackedForHotseatPrediction(mLastDragItem)) { sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); } + if (mLastDragItem != null && isTrackedForWidgetPrediction(mLastDragItem)) { + sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_WIDGETS_PREDICTION); + } } else if (event == LAUNCHER_HOTSEAT_PREDICTION_PINNED) { if (isTrackedForHotseatPrediction(atomInfo)) { sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION); @@ -302,19 +310,4 @@ public class AppEventProducer implements StatsLogConsumer { return TextUtils.isEmpty(componentNameString) ? null : ComponentName.unflattenFromString(componentNameString); } - - /** - * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors - */ - private static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) { - ContainerInfo ci = info.getContainerInfo(); - switch (ci.getContainerCase()) { - case HOTSEAT: - return true; - case WORKSPACE: - return ci.getWorkspace().getPageIndex() == 0; - default: - return false; - } - } } diff --git a/quickstep/src/com/android/launcher3/model/PredictionHelper.java b/quickstep/src/com/android/launcher3/model/PredictionHelper.java new file mode 100644 index 0000000000..738dd83cbc --- /dev/null +++ b/quickstep/src/com/android/launcher3/model/PredictionHelper.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2021 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 static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.WORKSPACE; + +import android.app.prediction.AppTarget; +import android.app.prediction.AppTargetEvent; +import android.app.prediction.AppTargetId; +import android.content.ComponentName; +import android.content.Context; + +import androidx.annotation.Nullable; + +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.Workspace; +import com.android.launcher3.logger.LauncherAtom; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.shortcuts.ShortcutKey; + +import java.util.Locale; + +/** Helper class with methods for converting launcher items to form usable by predictors */ +public final class PredictionHelper { + private static final String APP_LOCATION_HOTSEAT = "hotseat"; + private static final String APP_LOCATION_WORKSPACE = "workspace"; + + /** + * Creates and returns an {@link AppTarget} object for an {@link ItemInfo}. Returns null + * if item type is not supported in predictions + */ + @Nullable + public static AppTarget getAppTargetFromItemInfo(Context context, ItemInfo info) { + if (info == null) return null; + if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET + && info instanceof LauncherAppWidgetInfo + && ((LauncherAppWidgetInfo) info).providerName != null) { + ComponentName cn = ((LauncherAppWidgetInfo) info).providerName; + return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()), + cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION + && info.getTargetComponent() != null) { + ComponentName cn = info.getTargetComponent(); + return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), + cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT + && info instanceof WorkspaceItemInfo) { + ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info); + //TODO: switch to using full shortcut info + return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()), + shortcutKey.componentName.getPackageName(), shortcutKey.user).build(); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { + return new AppTarget.Builder(new AppTargetId("folder:" + info.id), + context.getPackageName(), info.user).build(); + } + return null; + } + + /** + * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item + * location using {@link ItemInfo} + */ + public static AppTargetEvent wrapAppTargetWithItemLocation( + AppTarget target, int action, ItemInfo info) { + String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]", + info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT + ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE, + info.screenId, info.cellX, info.cellY, info.spanX, info.spanY); + return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build(); + } + + /** + * Helper method to determine if {@link ItemInfo} should be tracked and reported to hotseat + * predictors + */ + public static boolean isTrackedForHotseatPrediction(ItemInfo info) { + return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || ( + info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP + && info.screenId == Workspace.FIRST_SCREEN_ID); + } + + /** + * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported to + * hotseat predictors + */ + public static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) { + LauncherAtom.ContainerInfo ci = info.getContainerInfo(); + switch (ci.getContainerCase()) { + case HOTSEAT: + return true; + case WORKSPACE: + return ci.getWorkspace().getPageIndex() == 0; + default: + return false; + } + } + + /** + * Helper method to determine if {@link ItemInfo} should be tracked and reported to widget + * predictors + */ + public static boolean isTrackedForWidgetPrediction(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET + && info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP; + } + + /** + * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported + * to widget predictors + */ + public static boolean isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info) { + return info.getItemCase() == LauncherAtom.ItemInfo.ItemCase.WIDGET + && info.getContainerInfo().getContainerCase() == WORKSPACE; + } +} diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index 55a140dffb..7794d27d26 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -25,8 +25,12 @@ import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICA import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.Utilities.getDevicePrefs; import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle; +import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo; +import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import static java.util.stream.Collectors.toCollection; + import android.app.StatsManager; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; @@ -39,6 +43,7 @@ import android.content.SharedPreferences; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; +import android.os.Bundle; import android.os.UserHandle; import android.util.Log; import android.util.StatsEvent; @@ -62,6 +67,7 @@ import com.android.launcher3.util.PersistedItemArray; import com.android.quickstep.logging.StatsLogCompatManager; import com.android.systemui.shared.system.SysUiStatsLog; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -75,6 +81,7 @@ public class QuickstepModelDelegate extends ModelDelegate { public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state"; private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS"; + private static final String BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets"; private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20; private static final boolean IS_DEBUG = false; @@ -272,6 +279,7 @@ public class QuickstepModelDelegate extends ModelDelegate { registerWidgetsPredictor(apm.createAppPredictionSession( new AppPredictionContext.Builder(context) .setUiSurface("widgets") + .setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel)) .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION) .build())); } @@ -306,12 +314,41 @@ public class QuickstepModelDelegate extends ModelDelegate { } private void onAppTargetEvent(AppTargetEvent event, int client) { - PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState; + PredictorState state; + switch(client) { + case CONTAINER_PREDICTION: + state = mAllAppsState; + break; + case CONTAINER_WIDGETS_PREDICTION: + state = mWidgetsRecommendationState; + break; + case CONTAINER_HOTSEAT_PREDICTION: + default: + state = mHotseatState; + break; + } if (state.predictor != null) { state.predictor.notifyAppTargetEvent(event); } } + private Bundle getBundleForWidgetsOnWorkspace(Context context, BgDataModel dataModel) { + Bundle bundle = new Bundle(); + ArrayList<AppTargetEvent> widgetEvents = + dataModel.getAllWorkspaceItems().stream() + .filter(PredictionHelper::isTrackedForWidgetPrediction) + .map(item -> { + AppTarget target = getAppTargetFromItemInfo(context, item); + if (target == null) return null; + return wrapAppTargetWithItemLocation( + target, AppTargetEvent.ACTION_PIN, item); + }) + .filter(Objects::nonNull) + .collect(toCollection(ArrayList::new)); + bundle.putParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, widgetEvents); + return bundle; + } + static class PredictorState { public final FixedContainerItems items; |