Merge "Send widget added and removed events to AiAi." into sc-v2-dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user