Loading Android.bp +16 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,19 @@ android_library { manifest: "tests/tapl/AndroidManifest.xml", platform_apis: true, } java_library_static { name: "launcher-log-protos-lite", srcs: [ "protos/*.proto", "proto_overrides/*.proto", ], sdk_version: "current", proto: { type: "lite", local_include_dirs:[ "protos", "proto_overrides", ], }, } go/quickstep/src/com/android/quickstep/util/ShelfPeekAnim.java +4 −0 Original line number Diff line number Diff line Loading @@ -24,4 +24,8 @@ public class ShelfPeekAnim { public enum ShelfAnimState { } public boolean isPeeking() { return false; } } quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml 0 → 100644 +17 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2019 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. --> <com.android.launcher3.uioverrides.PredictedAppIcon style="@style/BaseIcon.Workspace" /> quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java +110 −60 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; Loading @@ -40,10 +41,9 @@ import com.android.launcher3.appprediction.DynamicItemCache; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; import com.android.launcher3.popup.PopupContainerWithArrow; 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.util.ComponentKey; Loading @@ -66,6 +66,9 @@ 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 APP_LOCATION_HOTSEAT = "hotseat"; private static final String APP_LOCATION_WORKSPACE = "workspace"; private static final String PREDICTION_CLIENT = "hotseat"; private DropTarget.DragObject mDragObject; Loading @@ -81,12 +84,14 @@ public class HotseatPredictionController implements DragController.DragListener, private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>(); public HotseatPredictionController(Launcher launcher) { mLauncher = launcher; mHotseat = launcher.getHotseat(); mAllAppsStore = mLauncher.getAppsView().getAppsStore(); mAllAppsStore.addUpdateListener(this); mDynamicItemCache = new DynamicItemCache(mLauncher, () -> fillGapsWithPrediction(false)); mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction); mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; launcher.getDeviceProfile().inv.addOnChangeListener(this); mHotseat.addOnAttachStateChangeListener(this); Loading @@ -102,16 +107,17 @@ public class HotseatPredictionController implements DragController.DragListener, mLauncher.getDragController().removeDragListener(this); } /** * Fills gaps in the hotseat with predictions */ public void fillGapsWithPrediction(boolean animate) { private void fillGapsWithPrediction() { fillGapsWithPrediction(false, null); } private void fillGapsWithPrediction(boolean animate, Runnable callback) { if (mDragObject != null) { return; } List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); int predictionIndex = 0; ArrayList<ItemInfo> newItemsToAdd = new ArrayList<>(); ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>(); for (int rank = 0; rank < mHotSeatItemsCount; rank++) { View child = mHotseat.getChildAt( mHotseat.getCellXFromOrder(rank), Loading @@ -130,21 +136,37 @@ public class HotseatPredictionController implements DragController.DragListener, WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++); if (isPredictedIcon(child)) { BubbleTextView icon = (BubbleTextView) child; PredictedAppIcon icon = (PredictedAppIcon) child; icon.applyFromWorkspaceItem(predictedItem); icon.finishBinding(); } else { newItemsToAdd.add(predictedItem); newItems.add(predictedItem); } preparePredictionInfo(predictedItem, rank); } mLauncher.bindItems(newItemsToAdd, animate); for (BubbleTextView icon : getPredictedIcons()) { icon.verifyHighRes(); icon.setOnLongClickListener((v) -> { PopupContainerWithArrow.showForIcon((BubbleTextView) v); return true; bindItems(newItems, animate, callback); } private void bindItems(List<WorkspaceItemInfo> itemsToAdd, boolean animate, Runnable callback) { AnimatorSet animationSet = new AnimatorSet(); for (WorkspaceItemInfo item : itemsToAdd) { PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item); mLauncher.getWorkspace().addInScreenFromBind(icon, item); icon.finishBinding(); if (animate) { animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1)); } } if (animate) { animationSet.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { if (callback != null) callback.run(); } }); icon.setBackgroundResource(R.drawable.predicted_icon_background); animationSet.start(); } else { if (callback != null) callback.run(); } } Loading Loading @@ -179,22 +201,30 @@ public class HotseatPredictionController implements DragController.DragListener, .build()); mAppPredictor.registerPredictionUpdates(mLauncher.getMainExecutor(), this::setPredictedApps); mAppPredictor.requestPredictionUpdate(); } private Bundle getAppPredictionContextExtra() { Bundle bundle = new Bundle(); ViewGroup vg = mHotseat.getShortcutsAndWidgets(); bundle.putParcelableArrayList(APP_LOCATION_HOTSEAT, getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets()))); bundle.putParcelableArrayList(APP_LOCATION_WORKSPACE, getPinnedAppTargetsInViewGroup( mLauncher.getWorkspace().getScreenWithId( Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets())); return bundle; } private ArrayList<AppTarget> getPinnedAppTargetsInViewGroup(ViewGroup viewGroup) { ArrayList<AppTarget> pinnedApps = new ArrayList<>(); for (int i = 0; i < vg.getChildCount(); i++) { View child = vg.getChildAt(i); for (int i = 0; i < viewGroup.getChildCount(); i++) { View child = viewGroup.getChildAt(i); if (isPinnedIcon(child)) { WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) child.getTag(); pinnedApps.add(getAppTargetFromItemInfo(itemInfo)); } } bundle.putParcelableArrayList("pinned_apps", pinnedApps); return bundle; return pinnedApps; } private void setPredictedApps(List<AppTarget> appTargets) { Loading @@ -210,7 +240,7 @@ public class HotseatPredictionController implements DragController.DragListener, mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache)); } updateDependencies(); fillGapsWithPrediction(false); fillGapsWithPrediction(); } private void updateDependencies() { Loading @@ -219,7 +249,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private void pinPrediction(ItemInfo info) { BubbleTextView icon = (BubbleTextView) mHotseat.getChildAt( PredictedAppIcon icon = (PredictedAppIcon) mHotseat.getChildAt( mHotseat.getCellXFromOrder(info.rank), mHotseat.getCellYFromOrder(info.rank)); if (icon == null) { Loading @@ -230,11 +260,9 @@ public class HotseatPredictionController implements DragController.DragListener, LauncherSettings.Favorites.CONTAINER_HOTSEAT, workspaceItemInfo.screenId, workspaceItemInfo.cellX, workspaceItemInfo.cellY); ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 1, 0.8f, 1).start(); icon.reset(); icon.applyFromWorkspaceItem(workspaceItemInfo); icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); icon.pin(workspaceItemInfo); AppTarget appTarget = getAppTargetFromItemInfo(workspaceItemInfo); notifyItemAction(appTarget, AppTargetEvent.ACTION_PIN); notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); } private List<WorkspaceItemInfo> mapToWorkspaceItemInfo( Loading Loading @@ -265,21 +293,23 @@ public class HotseatPredictionController implements DragController.DragListener, return predictedApps; } private List<BubbleTextView> getPredictedIcons() { List<BubbleTextView> icons = new ArrayList<>(); private List<PredictedAppIcon> getPredictedIcons() { List<PredictedAppIcon> icons = new ArrayList<>(); ViewGroup vg = mHotseat.getShortcutsAndWidgets(); for (int i = 0; i < vg.getChildCount(); i++) { View child = vg.getChildAt(i); if (isPredictedIcon(child)) { icons.add((BubbleTextView) child); icons.add((PredictedAppIcon) child); } } return icons; } private void removePredictedApps(boolean animate) { for (BubbleTextView icon : getPredictedIcons()) { if (animate) { private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines) { for (PredictedAppIcon icon : getPredictedIcons()) { int rank = ((WorkspaceItemInfo) icon.getTag()).rank; outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing( mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon)); icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { Loading @@ -288,24 +318,26 @@ public class HotseatPredictionController implements DragController.DragListener, } } }); } else { if (icon.getParent() != null) { mHotseat.removeView(icon); } } } } private void notifyItemAction(AppTarget target, int action) { private void notifyItemAction(AppTarget target, String location, int action) { if (mAppPredictor != null) { mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, action).build()); mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build()); } } @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { removePredictedApps(true); removePredictedApps(mOutlineDrawings); mDragObject = dragObject; if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.addDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); } @Override Loading @@ -315,14 +347,29 @@ public class HotseatPredictionController implements DragController.DragListener, } ItemInfo dragInfo = mDragObject.dragInfo; if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) { AppTarget appTarget = getAppTargetFromItemInfo(dragInfo); if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN); } if (!isInFirstPage(dragInfo) && isInFirstPage(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN); } if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(getAppTargetFromItemInfo(dragInfo), AppTargetEvent.ACTION_PIN); } else if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(getAppTargetFromItemInfo(dragInfo), APPTARGET_ACTION_UNPIN); notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); } if (isInFirstPage(dragInfo) && !isInFirstPage(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, AppTargetEvent.ACTION_PIN); } } mDragObject = null; fillGapsWithPrediction(true); fillGapsWithPrediction(true, () -> { if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.removeDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); mOutlineDrawings.clear(); }); } @Nullable Loading Loading @@ -351,8 +398,7 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onAppsUpdated() { updateDependencies(); fillGapsWithPrediction(false); fillGapsWithPrediction(); } @Override Loading @@ -375,7 +421,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private static boolean isPredictedIcon(View view) { return view instanceof BubbleTextView && view.getTag() instanceof WorkspaceItemInfo return view instanceof PredictedAppIcon && view.getTag() instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) view.getTag()).container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; } Loading @@ -385,7 +431,7 @@ public class HotseatPredictionController implements DragController.DragListener, return false; } ItemInfo info = (ItemInfo) view.getTag(); return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT && ( return info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION && ( info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT); } Loading @@ -394,11 +440,15 @@ public class HotseatPredictionController implements DragController.DragListener, return itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT; } private static boolean isInFirstPage(ItemInfo itemInfo) { return itemInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && itemInfo.screenId == Workspace.FIRST_SCREEN_ID; } private static AppTarget getAppTargetFromItemInfo(ItemInfo info) { if (info.getTargetComponent() == null) return null; return new AppTarget.Builder( new AppTargetId("app:" + info.getTargetComponent().getPackageName()), info.getTargetComponent().getPackageName(), info.user).setClassName( info.getTargetComponent().getClassName()).build(); ComponentName cn = info.getTargetComponent(); return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); } } quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +26 −1 Original line number Diff line number Diff line Loading @@ -21,8 +21,15 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherStateManager.ANIM_ALL; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator; Loading @@ -40,6 +47,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.SpringAnimationBuilder; import com.android.quickstep.util.AppWindowAnimationHelper; Loading @@ -56,6 +64,9 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti public static final int INDEX_SHELF_ANIM = 0; public static final int INDEX_RECENTS_FADE_ANIM = 1; public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2; public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3; public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300; public LauncherAppTransitionManagerImpl(Context context) { super(context); Loading Loading @@ -145,7 +156,7 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti @Override public int getStateElementAnimationsCount() { return 3; return 4; } @Override Loading Loading @@ -191,6 +202,20 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti .setStiffness(250) .setValues(values) .build(mLauncher); case INDEX_PAUSE_TO_OVERVIEW_ANIM: { AnimatorSetBuilder builder = new AnimatorSetBuilder(); builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2); builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3); if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) { builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2); builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2); } LauncherStateManager stateManager = mLauncher.getStateManager(); return stateManager.createAtomicAnimation( stateManager.getCurrentStableState(), OVERVIEW, builder, ANIM_ALL, ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW); } default: return super.createStateElementAnimation(index, values); } Loading Loading
Android.bp +16 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,19 @@ android_library { manifest: "tests/tapl/AndroidManifest.xml", platform_apis: true, } java_library_static { name: "launcher-log-protos-lite", srcs: [ "protos/*.proto", "proto_overrides/*.proto", ], sdk_version: "current", proto: { type: "lite", local_include_dirs:[ "protos", "proto_overrides", ], }, }
go/quickstep/src/com/android/quickstep/util/ShelfPeekAnim.java +4 −0 Original line number Diff line number Diff line Loading @@ -24,4 +24,8 @@ public class ShelfPeekAnim { public enum ShelfAnimState { } public boolean isPeeking() { return false; } }
quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml 0 → 100644 +17 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2019 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. --> <com.android.launcher3.uioverrides.PredictedAppIcon style="@style/BaseIcon.Workspace" />
quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java +110 −60 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; Loading @@ -40,10 +41,9 @@ import com.android.launcher3.appprediction.DynamicItemCache; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; import com.android.launcher3.popup.PopupContainerWithArrow; 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.util.ComponentKey; Loading @@ -66,6 +66,9 @@ 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 APP_LOCATION_HOTSEAT = "hotseat"; private static final String APP_LOCATION_WORKSPACE = "workspace"; private static final String PREDICTION_CLIENT = "hotseat"; private DropTarget.DragObject mDragObject; Loading @@ -81,12 +84,14 @@ public class HotseatPredictionController implements DragController.DragListener, private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>(); public HotseatPredictionController(Launcher launcher) { mLauncher = launcher; mHotseat = launcher.getHotseat(); mAllAppsStore = mLauncher.getAppsView().getAppsStore(); mAllAppsStore.addUpdateListener(this); mDynamicItemCache = new DynamicItemCache(mLauncher, () -> fillGapsWithPrediction(false)); mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction); mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; launcher.getDeviceProfile().inv.addOnChangeListener(this); mHotseat.addOnAttachStateChangeListener(this); Loading @@ -102,16 +107,17 @@ public class HotseatPredictionController implements DragController.DragListener, mLauncher.getDragController().removeDragListener(this); } /** * Fills gaps in the hotseat with predictions */ public void fillGapsWithPrediction(boolean animate) { private void fillGapsWithPrediction() { fillGapsWithPrediction(false, null); } private void fillGapsWithPrediction(boolean animate, Runnable callback) { if (mDragObject != null) { return; } List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); int predictionIndex = 0; ArrayList<ItemInfo> newItemsToAdd = new ArrayList<>(); ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>(); for (int rank = 0; rank < mHotSeatItemsCount; rank++) { View child = mHotseat.getChildAt( mHotseat.getCellXFromOrder(rank), Loading @@ -130,21 +136,37 @@ public class HotseatPredictionController implements DragController.DragListener, WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++); if (isPredictedIcon(child)) { BubbleTextView icon = (BubbleTextView) child; PredictedAppIcon icon = (PredictedAppIcon) child; icon.applyFromWorkspaceItem(predictedItem); icon.finishBinding(); } else { newItemsToAdd.add(predictedItem); newItems.add(predictedItem); } preparePredictionInfo(predictedItem, rank); } mLauncher.bindItems(newItemsToAdd, animate); for (BubbleTextView icon : getPredictedIcons()) { icon.verifyHighRes(); icon.setOnLongClickListener((v) -> { PopupContainerWithArrow.showForIcon((BubbleTextView) v); return true; bindItems(newItems, animate, callback); } private void bindItems(List<WorkspaceItemInfo> itemsToAdd, boolean animate, Runnable callback) { AnimatorSet animationSet = new AnimatorSet(); for (WorkspaceItemInfo item : itemsToAdd) { PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item); mLauncher.getWorkspace().addInScreenFromBind(icon, item); icon.finishBinding(); if (animate) { animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1)); } } if (animate) { animationSet.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { if (callback != null) callback.run(); } }); icon.setBackgroundResource(R.drawable.predicted_icon_background); animationSet.start(); } else { if (callback != null) callback.run(); } } Loading Loading @@ -179,22 +201,30 @@ public class HotseatPredictionController implements DragController.DragListener, .build()); mAppPredictor.registerPredictionUpdates(mLauncher.getMainExecutor(), this::setPredictedApps); mAppPredictor.requestPredictionUpdate(); } private Bundle getAppPredictionContextExtra() { Bundle bundle = new Bundle(); ViewGroup vg = mHotseat.getShortcutsAndWidgets(); bundle.putParcelableArrayList(APP_LOCATION_HOTSEAT, getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets()))); bundle.putParcelableArrayList(APP_LOCATION_WORKSPACE, getPinnedAppTargetsInViewGroup( mLauncher.getWorkspace().getScreenWithId( Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets())); return bundle; } private ArrayList<AppTarget> getPinnedAppTargetsInViewGroup(ViewGroup viewGroup) { ArrayList<AppTarget> pinnedApps = new ArrayList<>(); for (int i = 0; i < vg.getChildCount(); i++) { View child = vg.getChildAt(i); for (int i = 0; i < viewGroup.getChildCount(); i++) { View child = viewGroup.getChildAt(i); if (isPinnedIcon(child)) { WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) child.getTag(); pinnedApps.add(getAppTargetFromItemInfo(itemInfo)); } } bundle.putParcelableArrayList("pinned_apps", pinnedApps); return bundle; return pinnedApps; } private void setPredictedApps(List<AppTarget> appTargets) { Loading @@ -210,7 +240,7 @@ public class HotseatPredictionController implements DragController.DragListener, mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache)); } updateDependencies(); fillGapsWithPrediction(false); fillGapsWithPrediction(); } private void updateDependencies() { Loading @@ -219,7 +249,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private void pinPrediction(ItemInfo info) { BubbleTextView icon = (BubbleTextView) mHotseat.getChildAt( PredictedAppIcon icon = (PredictedAppIcon) mHotseat.getChildAt( mHotseat.getCellXFromOrder(info.rank), mHotseat.getCellYFromOrder(info.rank)); if (icon == null) { Loading @@ -230,11 +260,9 @@ public class HotseatPredictionController implements DragController.DragListener, LauncherSettings.Favorites.CONTAINER_HOTSEAT, workspaceItemInfo.screenId, workspaceItemInfo.cellX, workspaceItemInfo.cellY); ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 1, 0.8f, 1).start(); icon.reset(); icon.applyFromWorkspaceItem(workspaceItemInfo); icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); icon.pin(workspaceItemInfo); AppTarget appTarget = getAppTargetFromItemInfo(workspaceItemInfo); notifyItemAction(appTarget, AppTargetEvent.ACTION_PIN); notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); } private List<WorkspaceItemInfo> mapToWorkspaceItemInfo( Loading Loading @@ -265,21 +293,23 @@ public class HotseatPredictionController implements DragController.DragListener, return predictedApps; } private List<BubbleTextView> getPredictedIcons() { List<BubbleTextView> icons = new ArrayList<>(); private List<PredictedAppIcon> getPredictedIcons() { List<PredictedAppIcon> icons = new ArrayList<>(); ViewGroup vg = mHotseat.getShortcutsAndWidgets(); for (int i = 0; i < vg.getChildCount(); i++) { View child = vg.getChildAt(i); if (isPredictedIcon(child)) { icons.add((BubbleTextView) child); icons.add((PredictedAppIcon) child); } } return icons; } private void removePredictedApps(boolean animate) { for (BubbleTextView icon : getPredictedIcons()) { if (animate) { private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines) { for (PredictedAppIcon icon : getPredictedIcons()) { int rank = ((WorkspaceItemInfo) icon.getTag()).rank; outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing( mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon)); icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { Loading @@ -288,24 +318,26 @@ public class HotseatPredictionController implements DragController.DragListener, } } }); } else { if (icon.getParent() != null) { mHotseat.removeView(icon); } } } } private void notifyItemAction(AppTarget target, int action) { private void notifyItemAction(AppTarget target, String location, int action) { if (mAppPredictor != null) { mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, action).build()); mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build()); } } @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { removePredictedApps(true); removePredictedApps(mOutlineDrawings); mDragObject = dragObject; if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.addDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); } @Override Loading @@ -315,14 +347,29 @@ public class HotseatPredictionController implements DragController.DragListener, } ItemInfo dragInfo = mDragObject.dragInfo; if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) { AppTarget appTarget = getAppTargetFromItemInfo(dragInfo); if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN); } if (!isInFirstPage(dragInfo) && isInFirstPage(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN); } if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(getAppTargetFromItemInfo(dragInfo), AppTargetEvent.ACTION_PIN); } else if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) { notifyItemAction(getAppTargetFromItemInfo(dragInfo), APPTARGET_ACTION_UNPIN); notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); } if (isInFirstPage(dragInfo) && !isInFirstPage(mDragObject.originalDragInfo)) { notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, AppTargetEvent.ACTION_PIN); } } mDragObject = null; fillGapsWithPrediction(true); fillGapsWithPrediction(true, () -> { if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.removeDelegatedCellDrawing(outlineDrawing); } mHotseat.invalidate(); mOutlineDrawings.clear(); }); } @Nullable Loading Loading @@ -351,8 +398,7 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onAppsUpdated() { updateDependencies(); fillGapsWithPrediction(false); fillGapsWithPrediction(); } @Override Loading @@ -375,7 +421,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private static boolean isPredictedIcon(View view) { return view instanceof BubbleTextView && view.getTag() instanceof WorkspaceItemInfo return view instanceof PredictedAppIcon && view.getTag() instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) view.getTag()).container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; } Loading @@ -385,7 +431,7 @@ public class HotseatPredictionController implements DragController.DragListener, return false; } ItemInfo info = (ItemInfo) view.getTag(); return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT && ( return info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION && ( info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT); } Loading @@ -394,11 +440,15 @@ public class HotseatPredictionController implements DragController.DragListener, return itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT; } private static boolean isInFirstPage(ItemInfo itemInfo) { return itemInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && itemInfo.screenId == Workspace.FIRST_SCREEN_ID; } private static AppTarget getAppTargetFromItemInfo(ItemInfo info) { if (info.getTargetComponent() == null) return null; return new AppTarget.Builder( new AppTargetId("app:" + info.getTargetComponent().getPackageName()), info.getTargetComponent().getPackageName(), info.user).setClassName( info.getTargetComponent().getClassName()).build(); ComponentName cn = info.getTargetComponent(); return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); } }
quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +26 −1 Original line number Diff line number Diff line Loading @@ -21,8 +21,15 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherStateManager.ANIM_ALL; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator; Loading @@ -40,6 +47,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.SpringAnimationBuilder; import com.android.quickstep.util.AppWindowAnimationHelper; Loading @@ -56,6 +64,9 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti public static final int INDEX_SHELF_ANIM = 0; public static final int INDEX_RECENTS_FADE_ANIM = 1; public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2; public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3; public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300; public LauncherAppTransitionManagerImpl(Context context) { super(context); Loading Loading @@ -145,7 +156,7 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti @Override public int getStateElementAnimationsCount() { return 3; return 4; } @Override Loading Loading @@ -191,6 +202,20 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti .setStiffness(250) .setValues(values) .build(mLauncher); case INDEX_PAUSE_TO_OVERVIEW_ANIM: { AnimatorSetBuilder builder = new AnimatorSetBuilder(); builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2); builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3); if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) { builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2); builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2); } LauncherStateManager stateManager = mLauncher.getStateManager(); return stateManager.createAtomicAnimation( stateManager.getCurrentStableState(), OVERVIEW, builder, ANIM_ALL, ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW); } default: return super.createStateElementAnimation(index, values); } Loading