diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 398489044e..b459b2dc3b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -58,6 +58,7 @@ android:enabled="true"> + diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java index d4bbfa2a52..3f29e433d9 100644 --- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java +++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java @@ -138,12 +138,12 @@ public class AppEventProducer implements StatsLogConsumer { if (mLastDragItem == null) { return; } - if (isTrackedForHotseatPrediction(atomInfo)) { - sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION); - } if (isTrackedForHotseatPrediction(mLastDragItem)) { sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); } + if (isTrackedForHotseatPrediction(atomInfo)) { + sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION); + } if (isTrackedForWidgetPrediction(atomInfo)) { sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index e152915038..435eae47ee 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -15,6 +15,11 @@ */ package com.android.launcher3.taskbar; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.ClipData; import android.content.ClipDescription; import android.content.Intent; @@ -27,7 +32,9 @@ import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.view.DragEvent; import android.view.MotionEvent; +import android.view.SurfaceControl; import android.view.View; +import android.view.ViewRootImpl; import androidx.annotation.Nullable; @@ -39,20 +46,25 @@ import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.accessibility.DragViewStateAnnouncer; +import com.android.launcher3.anim.Interpolators; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragDriver; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; +import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; +import com.android.launcher3.util.LauncherBindableItemsContainer; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ClipDescriptionCompat; import com.android.systemui.shared.system.LauncherAppsCompat; @@ -66,6 +78,8 @@ import java.util.Arrays; public class TaskbarDragController extends DragController implements TaskbarControllers.LoggableTaskbarController { + private static boolean DEBUG_DRAG_SHADOW_SURFACE = false; + private final int mDragIconSize; private final int[] mTempXY = new int[2]; @@ -78,6 +92,9 @@ public class TaskbarDragController extends DragController { switch (dragEvent.getAction()) { @@ -356,7 +377,12 @@ public class TaskbarDragController extends DragController= 0) { + // Since folders close when the drag starts, target the folder icon instead + LauncherBindableItemsContainer.ItemOperator op = (info, v) -> { + if (info instanceof FolderInfo && v instanceof FolderIcon) { + FolderInfo fi = (FolderInfo) info; + for (WorkspaceItemInfo si : fi.contents) { + if (si.id == item.id) { + // Found the parent + return true; + } + } + } + return false; + }; + target = taskbarViewController.mapOverItems(op); + } + } + + // Finish any pending return animation before starting a new drag + if (mReturnAnimator != null) { + mReturnAnimator.end(); + } + + float fromX = dragEvent.getX() - dragEvent.getOffsetX(); + float fromY = dragEvent.getY() - dragEvent.getOffsetY(); + int[] toPosition = target.getLocationOnScreen(); + float toScale = (float) target.getWidth() / mDragIconSize; + float toAlpha = (target == btv) ? 1f : 0f; + final ViewRootImpl viewRoot = target.getViewRootImpl(); + SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); + mReturnAnimator = ValueAnimator.ofFloat(0f, 1f); + mReturnAnimator.setDuration(300); + mReturnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mReturnAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float t = animation.getAnimatedFraction(); + float accelT = Interpolators.ACCEL_2.getInterpolation(t); + float scale = 1f - t * (1f - toScale); + float alpha = 1f - accelT * (1f - toAlpha); + tx.setPosition(dragSurface, Utilities.mapRange(t, fromX, toPosition[0]), + Utilities.mapRange(t, fromY, toPosition[1])); + tx.setScale(dragSurface, scale, scale); + tx.setAlpha(dragSurface, alpha); + tx.apply(); + } + }); + mReturnAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + cleanUpSurface(); + } + + @Override + public void onAnimationEnd(Animator animation) { + cleanUpSurface(); + } + + private void cleanUpSurface() { + maybeOnDragEnd(); + // Synchronize removing the drag surface with the next draw after calling + // maybeOnDragEnd() + viewRoot.consumeNextDraw((transaction) -> { + transaction.remove(dragSurface); + transaction.apply(); + tx.close(); + }); + viewRoot.getView().invalidate(); + mReturnAnimator = null; + } + }); + mReturnAnimator.start(); + } + @Override protected float getX(MotionEvent ev) { // We will resize to fill the screen while dragging, so use screen coordinates. This ensures diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index fddd1ed6fb..ade58a9b7e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -32,6 +32,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Insettable; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.model.data.FolderInfo; @@ -214,7 +215,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } if (mAllAppsButton != null) { - addView(mAllAppsButton); + int index = Utilities.isRtl(getResources()) ? 0 : getChildCount(); + addView(mAllAppsButton, index); } } @@ -316,6 +318,13 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar return icons; } + /** + * Returns the all apps button in the taskbar. + */ + public View getAllAppsButtonView() { + return mAllAppsButton; + } + // FolderIconParent implemented methods. @Override @@ -357,13 +366,18 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar return getVisibility() == VISIBLE; } - protected void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) { + /** + * Maps {@code op} over all the child views, returning the view that {@code op} evaluates + * {@code true} for, or {@code null} if none satisfy {@code op}. + */ + protected View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) { // map over all the shortcuts on the taskbar for (int i = 0; i < getChildCount(); i++) { View item = getChildAt(i); if (op.evaluate((ItemInfo) item.getTag(), item)) { - return; + return item; } } + return null; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 778040dbc1..62f1fa5412 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -164,6 +164,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar return mTaskbarView.getIconViews(); } + public View getAllAppsButtonView() { + return mTaskbarView.getAllAppsButtonView(); + } + public AnimatedFloat getTaskbarIconScaleForStash() { return mTaskbarIconScaleForStash; } @@ -235,7 +239,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() && i == count - 1) { // Note that there is no All Apps button in the hotseat, this position is only used // as its convenient for animation purposes. - positionInHotseat = mActivity.getDeviceProfile().inv.numShownHotseatIcons; + positionInHotseat = Utilities.isRtl(child.getResources()) + ? -1 + : mActivity.getDeviceProfile().inv.numShownHotseatIcons; setter.setViewAlpha(child, 0, LINEAR); } else if (child.getTag() instanceof ItemInfo) { @@ -268,8 +274,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY()); } - public void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) { - mTaskbarView.mapOverItems(op); + public View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) { + return mTaskbarView.mapOverItems(op); } /** diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index e218db1043..2cb7100378 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1198,10 +1198,10 @@ public abstract class AbsSwipeUpHandler, // We probably never received an animation controller, skip logging. return; } - int pageIndex = endTarget == LAST_TASK + int pageIndex = endTarget == LAST_TASK || mRecentsView == null ? LOG_NO_OP_PAGE_INDEX : mRecentsView.getNextPage(); - // TODO: set correct container using the pageIndex + logger.withRank(pageIndex); logger.log(event); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index fb4a7fd38b..661aa00a6a 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -125,6 +125,7 @@ import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.allapps.BaseAllAppsContainerView; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.PropertyListBuilder; @@ -1579,6 +1580,7 @@ public class Launcher extends StatefulActivity implements Launche boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this); hideKeyboard(); + if (isActionMain) { if (!internalStateHandled) { // In all these cases, only animate if we're already on home @@ -1607,6 +1609,8 @@ public class Launcher extends StatefulActivity implements Launche handleGestureContract(intent); } else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) { showAllAppsFromIntent(alreadyOnHome); + } else if (Intent.ACTION_SHOW_WORK_APPS.equals(intent.getAction())) { + showAllAppsWorkTabFromIntent(alreadyOnHome); } TraceHelper.INSTANCE.endSection(traceToken); @@ -1617,6 +1621,11 @@ public class Launcher extends StatefulActivity implements Launche getStateManager().goToState(ALL_APPS, alreadyOnHome); } + private void showAllAppsWorkTabFromIntent(boolean alreadyOnHome) { + showAllAppsFromIntent(alreadyOnHome); + mAppsView.switchToTab(BaseAllAppsContainerView.AdapterHolder.WORK); + } + /** * Handles gesture nav contract */ diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java index e8dcdbd46b..2b2c7c55c5 100644 --- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java @@ -331,6 +331,16 @@ public abstract class BaseAllAppsContainerView users = workspaceItemInfos.stream().map(w -> w.user) .collect(Collectors.toSet()); if (users.size() == 1 && !users.contains(Process.myUserHandle())) { - String workFolderName = context.getString(R.string.work_folder_name); + StringCache cache = ActivityContext.lookupContext(context).getStringCache(); + String workFolderName = cache != null + ? cache.workFolderName : context.getString(R.string.work_folder_name); setAsLastSuggestion(nameInfos, workFolderName); }