Cache hotseat predictions
Saves a list of ComponentKeys to allow launcher to show predictions while AiAi is booting up.
Cache is invalidated on new predictor creation, on user changing home screen set up,
or after receiving an empty list of predictions from AiAi.
Bug: 152582306
Test: Manual
Change-Id: I2047aa3bcbf8bc1ef9b7b6a7925ef14a3433a3b4
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/ComponentKeyMapper.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/ComponentKeyMapper.java
index fdb8e4c..d200868 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/ComponentKeyMapper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/ComponentKeyMapper.java
@@ -21,7 +21,6 @@
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
public class ComponentKeyMapper {
@@ -57,9 +56,8 @@
return item;
} else if (getComponentClass().equals(COMPONENT_CLASS_MARKER)) {
return mCache.getInstantApp(componentKey.componentName.getPackageName());
- } else if (componentKey instanceof ShortcutKey) {
- return mCache.getShortcutInfo((ShortcutKey) componentKey);
+ } else {
+ return mCache.getShortcutInfo(componentKey);
}
- return null;
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java
index 6c4bfe8..ab96b1340 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java
@@ -45,6 +45,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.InstantAppResolver;
import java.util.ArrayList;
@@ -76,7 +77,7 @@
private final Runnable mOnUpdateCallback;
private final IconCache mIconCache;
- private final Map<ShortcutKey, WorkspaceItemInfo> mShortcuts;
+ private final Map<ComponentKey, WorkspaceItemInfo> mShortcuts;
private final Map<String, InstantAppItemInfo> mInstantApps;
public DynamicItemCache(Context context, Runnable onUpdateCallback) {
@@ -230,7 +231,7 @@
}
@MainThread
- public WorkspaceItemInfo getShortcutInfo(ShortcutKey key) {
+ public WorkspaceItemInfo getShortcutInfo(ComponentKey key) {
return mShortcuts.get(key);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 7c00287..e7398ab 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -97,6 +97,8 @@
//TODO: replace this with AppTargetEvent.ACTION_UNPIN (b/144119543)
private static final int APPTARGET_ACTION_UNPIN = 4;
+ private static final String PREDICTED_ITEMS_CACHE_KEY = "predicted_item_keys";
+
private static final String APP_LOCATION_HOTSEAT = "hotseat";
private static final String APP_LOCATION_WORKSPACE = "workspace";
@@ -119,6 +121,7 @@
private AllAppsStore mAllAppsStore;
private AnimatorSet mIconRemoveAnimators;
private boolean mUIUpdatePaused = false;
+ private boolean mRequiresCacheUpdate = false;
private HotseatEduController mHotseatEduController;
@@ -145,6 +148,7 @@
if (mHotseat.isAttachedToWindow()) {
onViewAttachedToWindow(mHotseat);
}
+ showCachedItems();
}
/**
@@ -294,6 +298,16 @@
mAppPredictor.requestPredictionUpdate();
}
+ private void showCachedItems() {
+ ArrayList<ComponentKey> componentKeys = getCachedComponentKeys();
+ mComponentKeyMappers.clear();
+ for (ComponentKey key : componentKeys) {
+ mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache));
+ }
+ updateDependencies();
+ fillGapsWithPrediction();
+ }
+
private Bundle getAppPredictionContextExtra() {
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT,
@@ -320,6 +334,7 @@
private void setPredictedApps(List<AppTarget> appTargets) {
mComponentKeyMappers.clear();
StringBuilder predictionLog = new StringBuilder("predictedApps: [\n");
+ ArrayList<ComponentKey> componentKeys = new ArrayList<>();
for (AppTarget appTarget : appTargets) {
ComponentKey key;
if (appTarget.getShortcutInfo() != null) {
@@ -328,6 +343,7 @@
key = new ComponentKey(new ComponentName(appTarget.getPackageName(),
appTarget.getClassName()), appTarget.getUser());
}
+ componentKeys.add(key);
predictionLog.append(key.toString());
predictionLog.append(",rank:");
predictionLog.append(appTarget.getRank());
@@ -342,6 +358,35 @@
} else if (mHotseatEduController != null) {
mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
}
+ // should invalidate cache if AiAi sends empty list of AppTargets
+ if (appTargets.isEmpty()) {
+ mRequiresCacheUpdate = true;
+ }
+ cachePredictionComponentKeys(componentKeys);
+ }
+
+ private void cachePredictionComponentKeys(ArrayList<ComponentKey> componentKeys) {
+ if (!mRequiresCacheUpdate) return;
+ StringBuilder builder = new StringBuilder();
+ for (ComponentKey componentKey : componentKeys) {
+ builder.append(componentKey);
+ builder.append("\n");
+ }
+ mLauncher.getDevicePrefs().edit().putString(PREDICTED_ITEMS_CACHE_KEY,
+ builder.toString()).apply();
+ mRequiresCacheUpdate = false;
+ }
+
+ private ArrayList<ComponentKey> getCachedComponentKeys() {
+ String cachedBlob = mLauncher.getDevicePrefs().getString(PREDICTED_ITEMS_CACHE_KEY, "");
+ ArrayList<ComponentKey> results = new ArrayList<>();
+ for (String line : cachedBlob.split("\n")) {
+ ComponentKey key = ComponentKey.fromString(line);
+ if (key != null) {
+ results.add(key);
+ }
+ }
+ return results;
}
private void updateDependencies() {
@@ -367,6 +412,7 @@
icon.pin(workspaceItemInfo);
AppTarget appTarget = getAppTargetFromItemInfo(workspaceItemInfo);
notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN);
+ mRequiresCacheUpdate = true;
}
private List<WorkspaceItemInfo> mapToWorkspaceItemInfo(
@@ -533,6 +579,7 @@
}
mDragObject = null;
fillGapsWithPrediction(true, this::removeOutlineDrawings);
+ mRequiresCacheUpdate = true;
}
@Nullable