Loading quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xmldeleted 100644 → 0 +0 −8 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <inset xmlns:android="http://schemas.android.com/apk/res/android" android:inset="@dimen/predicted_icon_background_inset"> <shape> <solid android:color="?attr/folderFillColor" /> <corners android:radius="@dimen/predicted_icon_background_corner_radius" /> </shape> </inset> quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java +101 −32 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; Loading @@ -61,7 +62,7 @@ import java.util.stream.IntStream; public class HotseatPredictionController implements DragController.DragListener, View.OnAttachStateChangeListener, SystemShortcut.Factory<QuickstepLauncher>, InvariantDeviceProfile.OnIDPChangeListener, AllAppsStore.OnUpdateListener, IconCache.ItemInfoUpdateReceiver { IconCache.ItemInfoUpdateReceiver, DragSource { private static final String TAG = "PredictiveHotseat"; private static final boolean DEBUG = false; Loading @@ -72,6 +73,9 @@ public class HotseatPredictionController implements DragController.DragListener, private static final String APP_LOCATION_HOTSEAT = "hotseat"; private static final String APP_LOCATION_WORKSPACE = "workspace"; private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps"; private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps"; private static final String PREDICTION_CLIENT = "hotseat"; private DropTarget.DragObject mDragObject; Loading @@ -79,7 +83,7 @@ public class HotseatPredictionController implements DragController.DragListener, private int mPredictedSpotsCount = 0; private Launcher mLauncher; private Hotseat mHotseat; private final Hotseat mHotseat; private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>(); Loading @@ -87,10 +91,18 @@ public class HotseatPredictionController implements DragController.DragListener, private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; private AnimatorSet mIconRemoveAnimators; private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>(); private static HotseatPredictionController sInstance; private final View.OnLongClickListener mPredictionLongClickListener = v -> { if (!ItemLongClickListener.canStartDrag(mLauncher)) return false; if (mLauncher.getWorkspace().isSwitchingState()) return false; // Start the drag mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions()); return false; }; public HotseatPredictionController(Launcher launcher) { mLauncher = launcher; Loading @@ -101,7 +113,9 @@ public class HotseatPredictionController implements DragController.DragListener, mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; launcher.getDeviceProfile().inv.addOnChangeListener(this); mHotseat.addOnAttachStateChangeListener(this); sInstance = this; if (mHotseat.isAttachedToWindow()) { onViewAttachedToWindow(mHotseat); } } @Override Loading @@ -125,6 +139,17 @@ public class HotseatPredictionController implements DragController.DragListener, List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); int predictionIndex = 0; ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>(); // make sure predicted icon removal and filling predictions don't step on each other if (mIconRemoveAnimators != null && mIconRemoveAnimators.isRunning()) { mIconRemoveAnimators.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { fillGapsWithPrediction(animate, callback); mIconRemoveAnimators.removeListener(this); } }); return; } for (int rank = 0; rank < mHotSeatItemsCount; rank++) { View child = mHotseat.getChildAt( mHotseat.getCellXFromOrder(rank), Loading @@ -140,12 +165,11 @@ public class HotseatPredictionController implements DragController.DragListener, } continue; } WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++); if (isPredictedIcon(child) && child.isEnabled()) { PredictedAppIcon icon = (PredictedAppIcon) child; icon.applyFromWorkspaceItem(predictedItem); icon.finishBinding(); icon.finishBinding(mPredictionLongClickListener); } else { newItems.add(predictedItem); } Loading @@ -160,7 +184,7 @@ public class HotseatPredictionController implements DragController.DragListener, for (WorkspaceItemInfo item : itemsToAdd) { PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item); mLauncher.getWorkspace().addInScreenFromBind(icon, item); icon.finishBinding(); icon.finishBinding(mPredictionLongClickListener); if (animate) { animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1)); } Loading Loading @@ -215,9 +239,9 @@ public class HotseatPredictionController implements DragController.DragListener, private Bundle getAppPredictionContextExtra() { Bundle bundle = new Bundle(); bundle.putParcelableArrayList(APP_LOCATION_HOTSEAT, bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT, getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets()))); bundle.putParcelableArrayList(APP_LOCATION_WORKSPACE, getPinnedAppTargetsInViewGroup( bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup( mLauncher.getWorkspace().getScreenWithId( Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets())); return bundle; Loading Loading @@ -285,9 +309,12 @@ public class HotseatPredictionController implements DragController.DragListener, ItemInfoWithIcon info = mapper.getApp(allAppsStore); if (info instanceof AppInfo) { WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((AppInfo) info); predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; predictedApps.add(predictedApp); } else if (info instanceof WorkspaceItemInfo) { predictedApps.add(new WorkspaceItemInfo((WorkspaceItemInfo) info)); WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((WorkspaceItemInfo) info); predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; predictedApps.add(predictedApp); } else { if (DEBUG) { Log.e(TAG, "Predicted app not found: " + mapper); Loading @@ -313,13 +340,27 @@ public class HotseatPredictionController implements DragController.DragListener, return icons; } private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines) { private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines, ItemInfo draggedInfo) { if (mIconRemoveAnimators != null) { mIconRemoveAnimators.end(); } mIconRemoveAnimators = new AnimatorSet(); removeOutlineDrawings(); for (PredictedAppIcon icon : getPredictedIcons()) { if (!icon.isEnabled()) { continue; } if (icon.getTag().equals(draggedInfo)) { mHotseat.removeView(icon); continue; } int rank = ((WorkspaceItemInfo) icon.getTag()).rank; outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing( mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon)); icon.setEnabled(false); icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() { ObjectAnimator animator = ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0); animator.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { if (icon.getParent() != null) { Loading @@ -327,10 +368,11 @@ public class HotseatPredictionController implements DragController.DragListener, } } }); mIconRemoveAnimators.play(animator); } mIconRemoveAnimators.start(); } private void notifyItemAction(AppTarget target, String location, int action) { if (mAppPredictor != null) { mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, Loading @@ -340,7 +382,7 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { removePredictedApps(mOutlineDrawings); removePredictedApps(mOutlineDrawings, dragObject.dragInfo); mDragObject = dragObject; if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { Loading @@ -354,15 +396,26 @@ public class HotseatPredictionController implements DragController.DragListener, if (mDragObject == null) { return; } ItemInfo dragInfo = mDragObject.dragInfo; if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) { ViewGroup hotseatVG = mHotseat.getShortcutsAndWidgets(); ViewGroup firstScreenVG = mLauncher.getWorkspace().getScreenWithId( Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets(); if (dragInfo instanceof WorkspaceItemInfo && dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && dragInfo.getTargetComponent() != null) { AppTarget appTarget = getAppTargetFromItemInfo(dragInfo); if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) { if (!getPinnedAppTargetsInViewGroup(hotseatVG).contains(appTarget)) { notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN); } } if (!isInFirstPage(dragInfo) && isInFirstPage(mDragObject.originalDragInfo)) { if (!getPinnedAppTargetsInViewGroup(firstScreenVG).contains(appTarget)) { notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN); } } if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); } Loading @@ -371,14 +424,7 @@ public class HotseatPredictionController implements DragController.DragListener, } } mDragObject = null; fillGapsWithPrediction(true, () -> { if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.removeDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); mOutlineDrawings.clear(); }); fillGapsWithPrediction(true, this::removeOutlineDrawings); } @Nullable Loading @@ -394,11 +440,20 @@ public class HotseatPredictionController implements DragController.DragListener, private void preparePredictionInfo(WorkspaceItemInfo itemInfo, int rank) { itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; itemInfo.rank = rank; itemInfo.cellX = rank; itemInfo.cellY = mHotSeatItemsCount - rank - 1; itemInfo.cellX = mHotseat.getCellXFromOrder(rank); itemInfo.cellY = mHotseat.getCellYFromOrder(rank); itemInfo.screenId = rank; } private void removeOutlineDrawings() { if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.removeDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); mOutlineDrawings.clear(); } @Override public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) { this.mHotSeatItemsCount = profile.numHotseatIcons; Loading @@ -415,6 +470,17 @@ public class HotseatPredictionController implements DragController.DragListener, } @Override public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) { //Does nothing } @Override public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target, LauncherLogProto.Target targetParent) { mHotseat.fillInLogContainerData(v, info, target, targetParent); } private class PinPrediction extends SystemShortcut<QuickstepLauncher> { private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) { Loading @@ -435,18 +501,22 @@ public class HotseatPredictionController implements DragController.DragListener, */ public static void fillInHybridHotseatRank( @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) { if (sInstance == null || itemInfo.getTargetComponent() == null QuickstepLauncher launcher = QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity(); if (launcher == null || launcher.getHotseatPredictionController() == null || itemInfo.getTargetComponent() == null || itemInfo.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) { return; } HotseatPredictionController controller = launcher.getHotseatPredictionController(); final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user); final List<ComponentKeyMapper> predictedApps = sInstance.mComponentKeyMappers; final List<ComponentKeyMapper> predictedApps = controller.mComponentKeyMappers; IntStream.range(0, predictedApps.size()) .filter((i) -> k.equals(predictedApps.get(i).getComponentKey())) .findFirst() .ifPresent((rank) -> target.predictedRank = Integer.parseInt(sInstance.mPredictedSpotsCount + "0" + rank)); Integer.parseInt(controller.mPredictedSpotsCount + "0" + rank)); } private static boolean isPredictedIcon(View view) { Loading @@ -461,8 +531,7 @@ public class HotseatPredictionController implements DragController.DragListener, } ItemInfo info = (ItemInfo) view.getTag(); return info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION && ( info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT); info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION); } private static boolean isInHotseat(ItemInfo itemInfo) { Loading quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java +3 −12 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.view.ViewGroup; import androidx.core.graphics.ColorUtils; import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; Loading @@ -37,7 +36,6 @@ import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.icons.IconNormalizer; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.views.DoubleShadowBubbleTextView; Loading @@ -47,14 +45,13 @@ import com.android.launcher3.views.DoubleShadowBubbleTextView; */ public class PredictedAppIcon extends DoubleShadowBubbleTextView { private static final float RING_EFFECT_RATIO = 0.12f; private static final float RING_EFFECT_RATIO = 0.11f; private DeviceProfile mDeviceProfile; private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private boolean mIsPinned = false; private int mNormalizedIconRadius; public PredictedAppIcon(Context context) { this(context, null, 0); } Loading Loading @@ -105,14 +102,8 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView { /** * prepares prediction icon for usage after bind */ public void finishBinding() { setOnLongClickListener((v) -> { PopupContainerWithArrow.showForIcon((BubbleTextView) v); if (getParent() != null) { getParent().requestDisallowInterceptTouchEvent(true); } return true; }); public void finishBinding(OnLongClickListener longClickListener) { setOnLongClickListener(longClickListener); ((CellLayout.LayoutParams) getLayoutParams()).canReorder = false; setTextVisibility(false); verifyHighRes(); Loading quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +7 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,13 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } /** * Returns Prediction controller for hybrid hotseat */ public HotseatPredictionController getHotseatPredictionController() { return mHotseatPredictionController; } /** * Recents logic that triggers when launcher state changes or launcher activity stops/resumes. */ Loading Loading
quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xmldeleted 100644 → 0 +0 −8 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <inset xmlns:android="http://schemas.android.com/apk/res/android" android:inset="@dimen/predicted_icon_background_inset"> <shape> <solid android:color="?attr/folderFillColor" /> <corners android:radius="@dimen/predicted_icon_background_corner_radius" /> </shape> </inset>
quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java +101 −32 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; Loading @@ -61,7 +62,7 @@ import java.util.stream.IntStream; public class HotseatPredictionController implements DragController.DragListener, View.OnAttachStateChangeListener, SystemShortcut.Factory<QuickstepLauncher>, InvariantDeviceProfile.OnIDPChangeListener, AllAppsStore.OnUpdateListener, IconCache.ItemInfoUpdateReceiver { IconCache.ItemInfoUpdateReceiver, DragSource { private static final String TAG = "PredictiveHotseat"; private static final boolean DEBUG = false; Loading @@ -72,6 +73,9 @@ public class HotseatPredictionController implements DragController.DragListener, private static final String APP_LOCATION_HOTSEAT = "hotseat"; private static final String APP_LOCATION_WORKSPACE = "workspace"; private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps"; private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps"; private static final String PREDICTION_CLIENT = "hotseat"; private DropTarget.DragObject mDragObject; Loading @@ -79,7 +83,7 @@ public class HotseatPredictionController implements DragController.DragListener, private int mPredictedSpotsCount = 0; private Launcher mLauncher; private Hotseat mHotseat; private final Hotseat mHotseat; private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>(); Loading @@ -87,10 +91,18 @@ public class HotseatPredictionController implements DragController.DragListener, private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; private AnimatorSet mIconRemoveAnimators; private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>(); private static HotseatPredictionController sInstance; private final View.OnLongClickListener mPredictionLongClickListener = v -> { if (!ItemLongClickListener.canStartDrag(mLauncher)) return false; if (mLauncher.getWorkspace().isSwitchingState()) return false; // Start the drag mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions()); return false; }; public HotseatPredictionController(Launcher launcher) { mLauncher = launcher; Loading @@ -101,7 +113,9 @@ public class HotseatPredictionController implements DragController.DragListener, mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; launcher.getDeviceProfile().inv.addOnChangeListener(this); mHotseat.addOnAttachStateChangeListener(this); sInstance = this; if (mHotseat.isAttachedToWindow()) { onViewAttachedToWindow(mHotseat); } } @Override Loading @@ -125,6 +139,17 @@ public class HotseatPredictionController implements DragController.DragListener, List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); int predictionIndex = 0; ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>(); // make sure predicted icon removal and filling predictions don't step on each other if (mIconRemoveAnimators != null && mIconRemoveAnimators.isRunning()) { mIconRemoveAnimators.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { fillGapsWithPrediction(animate, callback); mIconRemoveAnimators.removeListener(this); } }); return; } for (int rank = 0; rank < mHotSeatItemsCount; rank++) { View child = mHotseat.getChildAt( mHotseat.getCellXFromOrder(rank), Loading @@ -140,12 +165,11 @@ public class HotseatPredictionController implements DragController.DragListener, } continue; } WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++); if (isPredictedIcon(child) && child.isEnabled()) { PredictedAppIcon icon = (PredictedAppIcon) child; icon.applyFromWorkspaceItem(predictedItem); icon.finishBinding(); icon.finishBinding(mPredictionLongClickListener); } else { newItems.add(predictedItem); } Loading @@ -160,7 +184,7 @@ public class HotseatPredictionController implements DragController.DragListener, for (WorkspaceItemInfo item : itemsToAdd) { PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item); mLauncher.getWorkspace().addInScreenFromBind(icon, item); icon.finishBinding(); icon.finishBinding(mPredictionLongClickListener); if (animate) { animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1)); } Loading Loading @@ -215,9 +239,9 @@ public class HotseatPredictionController implements DragController.DragListener, private Bundle getAppPredictionContextExtra() { Bundle bundle = new Bundle(); bundle.putParcelableArrayList(APP_LOCATION_HOTSEAT, bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT, getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets()))); bundle.putParcelableArrayList(APP_LOCATION_WORKSPACE, getPinnedAppTargetsInViewGroup( bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup( mLauncher.getWorkspace().getScreenWithId( Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets())); return bundle; Loading Loading @@ -285,9 +309,12 @@ public class HotseatPredictionController implements DragController.DragListener, ItemInfoWithIcon info = mapper.getApp(allAppsStore); if (info instanceof AppInfo) { WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((AppInfo) info); predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; predictedApps.add(predictedApp); } else if (info instanceof WorkspaceItemInfo) { predictedApps.add(new WorkspaceItemInfo((WorkspaceItemInfo) info)); WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((WorkspaceItemInfo) info); predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; predictedApps.add(predictedApp); } else { if (DEBUG) { Log.e(TAG, "Predicted app not found: " + mapper); Loading @@ -313,13 +340,27 @@ public class HotseatPredictionController implements DragController.DragListener, return icons; } private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines) { private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines, ItemInfo draggedInfo) { if (mIconRemoveAnimators != null) { mIconRemoveAnimators.end(); } mIconRemoveAnimators = new AnimatorSet(); removeOutlineDrawings(); for (PredictedAppIcon icon : getPredictedIcons()) { if (!icon.isEnabled()) { continue; } if (icon.getTag().equals(draggedInfo)) { mHotseat.removeView(icon); continue; } int rank = ((WorkspaceItemInfo) icon.getTag()).rank; outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing( mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon)); icon.setEnabled(false); icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() { ObjectAnimator animator = ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0); animator.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { if (icon.getParent() != null) { Loading @@ -327,10 +368,11 @@ public class HotseatPredictionController implements DragController.DragListener, } } }); mIconRemoveAnimators.play(animator); } mIconRemoveAnimators.start(); } private void notifyItemAction(AppTarget target, String location, int action) { if (mAppPredictor != null) { mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, Loading @@ -340,7 +382,7 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { removePredictedApps(mOutlineDrawings); removePredictedApps(mOutlineDrawings, dragObject.dragInfo); mDragObject = dragObject; if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { Loading @@ -354,15 +396,26 @@ public class HotseatPredictionController implements DragController.DragListener, if (mDragObject == null) { return; } ItemInfo dragInfo = mDragObject.dragInfo; if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) { ViewGroup hotseatVG = mHotseat.getShortcutsAndWidgets(); ViewGroup firstScreenVG = mLauncher.getWorkspace().getScreenWithId( Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets(); if (dragInfo instanceof WorkspaceItemInfo && dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && dragInfo.getTargetComponent() != null) { AppTarget appTarget = getAppTargetFromItemInfo(dragInfo); if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) { if (!getPinnedAppTargetsInViewGroup(hotseatVG).contains(appTarget)) { notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN); } } if (!isInFirstPage(dragInfo) && isInFirstPage(mDragObject.originalDragInfo)) { if (!getPinnedAppTargetsInViewGroup(firstScreenVG).contains(appTarget)) { notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN); } } if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); } Loading @@ -371,14 +424,7 @@ public class HotseatPredictionController implements DragController.DragListener, } } mDragObject = null; fillGapsWithPrediction(true, () -> { if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.removeDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); mOutlineDrawings.clear(); }); fillGapsWithPrediction(true, this::removeOutlineDrawings); } @Nullable Loading @@ -394,11 +440,20 @@ public class HotseatPredictionController implements DragController.DragListener, private void preparePredictionInfo(WorkspaceItemInfo itemInfo, int rank) { itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; itemInfo.rank = rank; itemInfo.cellX = rank; itemInfo.cellY = mHotSeatItemsCount - rank - 1; itemInfo.cellX = mHotseat.getCellXFromOrder(rank); itemInfo.cellY = mHotseat.getCellYFromOrder(rank); itemInfo.screenId = rank; } private void removeOutlineDrawings() { if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.removeDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); mOutlineDrawings.clear(); } @Override public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) { this.mHotSeatItemsCount = profile.numHotseatIcons; Loading @@ -415,6 +470,17 @@ public class HotseatPredictionController implements DragController.DragListener, } @Override public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) { //Does nothing } @Override public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target, LauncherLogProto.Target targetParent) { mHotseat.fillInLogContainerData(v, info, target, targetParent); } private class PinPrediction extends SystemShortcut<QuickstepLauncher> { private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) { Loading @@ -435,18 +501,22 @@ public class HotseatPredictionController implements DragController.DragListener, */ public static void fillInHybridHotseatRank( @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) { if (sInstance == null || itemInfo.getTargetComponent() == null QuickstepLauncher launcher = QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity(); if (launcher == null || launcher.getHotseatPredictionController() == null || itemInfo.getTargetComponent() == null || itemInfo.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) { return; } HotseatPredictionController controller = launcher.getHotseatPredictionController(); final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user); final List<ComponentKeyMapper> predictedApps = sInstance.mComponentKeyMappers; final List<ComponentKeyMapper> predictedApps = controller.mComponentKeyMappers; IntStream.range(0, predictedApps.size()) .filter((i) -> k.equals(predictedApps.get(i).getComponentKey())) .findFirst() .ifPresent((rank) -> target.predictedRank = Integer.parseInt(sInstance.mPredictedSpotsCount + "0" + rank)); Integer.parseInt(controller.mPredictedSpotsCount + "0" + rank)); } private static boolean isPredictedIcon(View view) { Loading @@ -461,8 +531,7 @@ public class HotseatPredictionController implements DragController.DragListener, } ItemInfo info = (ItemInfo) view.getTag(); return info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION && ( info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT); info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION); } private static boolean isInHotseat(ItemInfo itemInfo) { Loading
quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java +3 −12 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.view.ViewGroup; import androidx.core.graphics.ColorUtils; import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; Loading @@ -37,7 +36,6 @@ import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.icons.IconNormalizer; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.views.DoubleShadowBubbleTextView; Loading @@ -47,14 +45,13 @@ import com.android.launcher3.views.DoubleShadowBubbleTextView; */ public class PredictedAppIcon extends DoubleShadowBubbleTextView { private static final float RING_EFFECT_RATIO = 0.12f; private static final float RING_EFFECT_RATIO = 0.11f; private DeviceProfile mDeviceProfile; private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private boolean mIsPinned = false; private int mNormalizedIconRadius; public PredictedAppIcon(Context context) { this(context, null, 0); } Loading Loading @@ -105,14 +102,8 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView { /** * prepares prediction icon for usage after bind */ public void finishBinding() { setOnLongClickListener((v) -> { PopupContainerWithArrow.showForIcon((BubbleTextView) v); if (getParent() != null) { getParent().requestDisallowInterceptTouchEvent(true); } return true; }); public void finishBinding(OnLongClickListener longClickListener) { setOnLongClickListener(longClickListener); ((CellLayout.LayoutParams) getLayoutParams()).canReorder = false; setTextVisibility(false); verifyHighRes(); Loading
quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +7 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,13 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } /** * Returns Prediction controller for hybrid hotseat */ public HotseatPredictionController getHotseatPredictionController() { return mHotseatPredictionController; } /** * Recents logic that triggers when launcher state changes or launcher activity stops/resumes. */ Loading