Loading quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +32 −35 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.launcher3.DropTarget; import com.android.launcher3.Hotseat; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherState; import com.android.launcher3.R; Loading @@ -56,6 +57,7 @@ import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.PredictionModel; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; Loading @@ -69,6 +71,7 @@ import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntArray; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -93,8 +96,6 @@ public class HotseatPredictionController implements DragController.DragListener, //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"; Loading @@ -115,11 +116,13 @@ public class HotseatPredictionController implements DragController.DragListener, private DynamicItemCache mDynamicItemCache; private final PredictionModel mPredictionModel; private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; private AnimatorSet mIconRemoveAnimators; private boolean mUIUpdatePaused = false; private boolean mRequiresCacheUpdate = false; private boolean mRequiresCacheUpdate = true; private boolean mIsCacheEmpty; private HotseatEduController mHotseatEduController; Loading @@ -138,15 +141,16 @@ public class HotseatPredictionController implements DragController.DragListener, mLauncher = launcher; mHotseat = launcher.getHotseat(); mAllAppsStore = mLauncher.getAppsView().getAppsStore(); mPredictionModel = LauncherAppState.INSTANCE.get(launcher).getPredictionModel(); mAllAppsStore.addUpdateListener(this); mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction); mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; launcher.getDeviceProfile().inv.addOnChangeListener(this); mHotseat.addOnAttachStateChangeListener(this); mIsCacheEmpty = mPredictionModel.getPredictionComponentKeys().isEmpty(); if (mHotseat.isAttachedToWindow()) { onViewAttachedToWindow(mHotseat); } showCachedItems(); } /** Loading Loading @@ -185,6 +189,11 @@ public class HotseatPredictionController implements DragController.DragListener, return; } List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); if (mComponentKeyMappers.isEmpty() != predictedApps.isEmpty()) { // Safely ignore update as AppsList is not ready yet. This will called again once // apps are ready (HotseatPredictionController#onAppsUpdated) return; } int predictionIndex = 0; ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>(); // make sure predicted icon removal and filling predictions don't step on each other Loading Loading @@ -305,14 +314,23 @@ public class HotseatPredictionController implements DragController.DragListener, mAppPredictor.requestPredictionUpdate(); } private void showCachedItems() { ArrayList<ComponentKey> componentKeys = getCachedComponentKeys(); /** * Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items. */ public void showCachedItems(List<AppInfo> apps, IntArray ranks) { int count = Math.min(ranks.size(), apps.size()); List<WorkspaceItemInfo> items = new ArrayList<>(count); for (int i = 0; i < count; i++) { WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i)); preparePredictionInfo(item, ranks.get(i)); items.add(item); } mComponentKeyMappers.clear(); for (ComponentKey key : componentKeys) { for (ComponentKey key : mPredictionModel.getPredictionComponentKeys()) { mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache)); } updateDependencies(); fillGapsWithPrediction(); bindItems(items, false, null); } private Bundle getAppPredictionContextExtra() { Loading Loading @@ -394,37 +412,16 @@ public class HotseatPredictionController implements DragController.DragListener, if (!isEduSeen() && mHotseatEduController != null) { mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); } // should invalidate cache if AiAi sends empty list of AppTargets if (appTargets.isEmpty()) { mRequiresCacheUpdate = true; } cachePredictionComponentKeys(componentKeys); cachePredictionComponentKeysIfNecessary(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(); private void cachePredictionComponentKeysIfNecessary(ArrayList<ComponentKey> componentKeys) { if (!mRequiresCacheUpdate && componentKeys.isEmpty() == mIsCacheEmpty) return; mPredictionModel.cachePredictionComponentKeys(componentKeys); mIsCacheEmpty = componentKeys.isEmpty(); 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() { mDynamicItemCache.updateDependencies(mComponentKeyMappers, mAllAppsStore, this, mHotSeatItemsCount); Loading quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +11 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; Loading @@ -58,6 +59,7 @@ import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchContro import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper.AsyncCommand; Loading @@ -70,6 +72,7 @@ import com.android.quickstep.views.TaskView; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class QuickstepLauncher extends BaseQuickstepLauncher { Loading Loading @@ -177,6 +180,14 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } @Override public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) { super.bindPredictedItems(appInfos, ranks); if (mHotseatPredictionController != null) { mHotseatPredictionController.showCachedItems(appInfos, ranks); } } @Override public void onDestroy() { super.onDestroy(); Loading src/com/android/launcher3/Launcher.java +3 −0 Original line number Diff line number Diff line Loading @@ -2225,6 +2225,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, workspace.requestLayout(); } @Override public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) { } /** * Add the views for a widget to the workspace. */ Loading src/com/android/launcher3/LauncherAppState.java +7 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.PredictionModel; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.pm.InstallSessionTracker; Loading @@ -57,6 +58,7 @@ public class LauncherAppState { private final IconCache mIconCache; private final WidgetPreviewLoader mWidgetCache; private final InvariantDeviceProfile mInvariantDeviceProfile; private final PredictionModel mPredictionModel; private SecureSettingsObserver mNotificationDotsObserver; private InstallSessionTracker mInstallSessionTracker; Loading Loading @@ -127,6 +129,7 @@ public class LauncherAppState { mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName); mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); mPredictionModel = new PredictionModel(mContext); } protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) { Loading Loading @@ -182,6 +185,10 @@ public class LauncherAppState { return mModel; } public PredictionModel getPredictionModel() { return mPredictionModel; } public WidgetPreviewLoader getWidgetCache() { return mWidgetCache; } Loading src/com/android/launcher3/model/BaseLoaderResults.java +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.launcher3.model; import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems; import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks; import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially; import android.util.Log; Loading Loading @@ -196,6 +197,10 @@ public abstract class BaseLoaderResults { // Load items on the current page. bindWorkspaceItems(currentWorkspaceItems, mainExecutor); bindAppWidgets(currentAppWidgets, mainExecutor); // Locate available spots for prediction using currentWorkspaceItems IntArray gaps = getMissingHotseatRanks(currentWorkspaceItems, idp.numHotseatIcons); bindPredictedItems(gaps, mainExecutor); // In case of validFirstPage, only bind the first screen, and defer binding the // remaining screens after first onDraw (and an optional the fade animation whichever // happens later). Loading Loading @@ -247,6 +252,11 @@ public abstract class BaseLoaderResults { } } private void bindPredictedItems(IntArray ranks, final Executor executor) { executeCallbacksTask( c -> c.bindPredictedItems(mBgDataModel.cachedPredictedItems, ranks), executor); } protected void executeCallbacksTask(CallbackTask task, Executor executor) { executor.execute(() -> { if (mMyBindingId != mBgDataModel.lastBindId) { Loading Loading
quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +32 −35 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.launcher3.DropTarget; import com.android.launcher3.Hotseat; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherState; import com.android.launcher3.R; Loading @@ -56,6 +57,7 @@ import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.PredictionModel; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; Loading @@ -69,6 +71,7 @@ import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntArray; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -93,8 +96,6 @@ public class HotseatPredictionController implements DragController.DragListener, //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"; Loading @@ -115,11 +116,13 @@ public class HotseatPredictionController implements DragController.DragListener, private DynamicItemCache mDynamicItemCache; private final PredictionModel mPredictionModel; private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; private AnimatorSet mIconRemoveAnimators; private boolean mUIUpdatePaused = false; private boolean mRequiresCacheUpdate = false; private boolean mRequiresCacheUpdate = true; private boolean mIsCacheEmpty; private HotseatEduController mHotseatEduController; Loading @@ -138,15 +141,16 @@ public class HotseatPredictionController implements DragController.DragListener, mLauncher = launcher; mHotseat = launcher.getHotseat(); mAllAppsStore = mLauncher.getAppsView().getAppsStore(); mPredictionModel = LauncherAppState.INSTANCE.get(launcher).getPredictionModel(); mAllAppsStore.addUpdateListener(this); mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction); mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; launcher.getDeviceProfile().inv.addOnChangeListener(this); mHotseat.addOnAttachStateChangeListener(this); mIsCacheEmpty = mPredictionModel.getPredictionComponentKeys().isEmpty(); if (mHotseat.isAttachedToWindow()) { onViewAttachedToWindow(mHotseat); } showCachedItems(); } /** Loading Loading @@ -185,6 +189,11 @@ public class HotseatPredictionController implements DragController.DragListener, return; } List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); if (mComponentKeyMappers.isEmpty() != predictedApps.isEmpty()) { // Safely ignore update as AppsList is not ready yet. This will called again once // apps are ready (HotseatPredictionController#onAppsUpdated) return; } int predictionIndex = 0; ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>(); // make sure predicted icon removal and filling predictions don't step on each other Loading Loading @@ -305,14 +314,23 @@ public class HotseatPredictionController implements DragController.DragListener, mAppPredictor.requestPredictionUpdate(); } private void showCachedItems() { ArrayList<ComponentKey> componentKeys = getCachedComponentKeys(); /** * Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items. */ public void showCachedItems(List<AppInfo> apps, IntArray ranks) { int count = Math.min(ranks.size(), apps.size()); List<WorkspaceItemInfo> items = new ArrayList<>(count); for (int i = 0; i < count; i++) { WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i)); preparePredictionInfo(item, ranks.get(i)); items.add(item); } mComponentKeyMappers.clear(); for (ComponentKey key : componentKeys) { for (ComponentKey key : mPredictionModel.getPredictionComponentKeys()) { mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache)); } updateDependencies(); fillGapsWithPrediction(); bindItems(items, false, null); } private Bundle getAppPredictionContextExtra() { Loading Loading @@ -394,37 +412,16 @@ public class HotseatPredictionController implements DragController.DragListener, if (!isEduSeen() && mHotseatEduController != null) { mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); } // should invalidate cache if AiAi sends empty list of AppTargets if (appTargets.isEmpty()) { mRequiresCacheUpdate = true; } cachePredictionComponentKeys(componentKeys); cachePredictionComponentKeysIfNecessary(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(); private void cachePredictionComponentKeysIfNecessary(ArrayList<ComponentKey> componentKeys) { if (!mRequiresCacheUpdate && componentKeys.isEmpty() == mIsCacheEmpty) return; mPredictionModel.cachePredictionComponentKeys(componentKeys); mIsCacheEmpty = componentKeys.isEmpty(); 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() { mDynamicItemCache.updateDependencies(mComponentKeyMappers, mAllAppsStore, this, mHotSeatItemsCount); Loading
quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +11 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; Loading @@ -58,6 +59,7 @@ import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchContro import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper.AsyncCommand; Loading @@ -70,6 +72,7 @@ import com.android.quickstep.views.TaskView; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class QuickstepLauncher extends BaseQuickstepLauncher { Loading Loading @@ -177,6 +180,14 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } @Override public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) { super.bindPredictedItems(appInfos, ranks); if (mHotseatPredictionController != null) { mHotseatPredictionController.showCachedItems(appInfos, ranks); } } @Override public void onDestroy() { super.onDestroy(); Loading
src/com/android/launcher3/Launcher.java +3 −0 Original line number Diff line number Diff line Loading @@ -2225,6 +2225,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, workspace.requestLayout(); } @Override public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) { } /** * Add the views for a widget to the workspace. */ Loading
src/com/android/launcher3/LauncherAppState.java +7 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.PredictionModel; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.pm.InstallSessionTracker; Loading @@ -57,6 +58,7 @@ public class LauncherAppState { private final IconCache mIconCache; private final WidgetPreviewLoader mWidgetCache; private final InvariantDeviceProfile mInvariantDeviceProfile; private final PredictionModel mPredictionModel; private SecureSettingsObserver mNotificationDotsObserver; private InstallSessionTracker mInstallSessionTracker; Loading Loading @@ -127,6 +129,7 @@ public class LauncherAppState { mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName); mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); mPredictionModel = new PredictionModel(mContext); } protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) { Loading Loading @@ -182,6 +185,10 @@ public class LauncherAppState { return mModel; } public PredictionModel getPredictionModel() { return mPredictionModel; } public WidgetPreviewLoader getWidgetCache() { return mWidgetCache; } Loading
src/com/android/launcher3/model/BaseLoaderResults.java +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.launcher3.model; import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems; import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks; import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially; import android.util.Log; Loading Loading @@ -196,6 +197,10 @@ public abstract class BaseLoaderResults { // Load items on the current page. bindWorkspaceItems(currentWorkspaceItems, mainExecutor); bindAppWidgets(currentAppWidgets, mainExecutor); // Locate available spots for prediction using currentWorkspaceItems IntArray gaps = getMissingHotseatRanks(currentWorkspaceItems, idp.numHotseatIcons); bindPredictedItems(gaps, mainExecutor); // In case of validFirstPage, only bind the first screen, and defer binding the // remaining screens after first onDraw (and an optional the fade animation whichever // happens later). Loading Loading @@ -247,6 +252,11 @@ public abstract class BaseLoaderResults { } } private void bindPredictedItems(IntArray ranks, final Executor executor) { executeCallbacksTask( c -> c.bindPredictedItems(mBgDataModel.cachedPredictedItems, ranks), executor); } protected void executeCallbacksTask(CallbackTask task, Executor executor) { executor.execute(() -> { if (mMyBindingId != mBgDataModel.lastBindId) { Loading