diff --git a/go/OWNERS b/go/OWNERS new file mode 100644 index 0000000000..903b3c4ef4 --- /dev/null +++ b/go/OWNERS @@ -0,0 +1,2 @@ +rajekumar@google.com +spivack@google.com diff --git a/go/quickstep/res/values/strings.xml b/go/quickstep/res/values/strings.xml index 71e2f3a5c5..61c8cd9343 100644 --- a/go/quickstep/res/values/strings.xml +++ b/go/quickstep/res/values/strings.xml @@ -10,5 +10,5 @@ Translate - Search + Lens diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java index 36a4e7fa35..872f168e20 100644 --- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java +++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java @@ -36,6 +36,8 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.R; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.TaskThumbnailView; @@ -51,6 +53,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH"; public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos"; public static final String ACTIONS_URL = "niu_actions_app_url"; + private static final String ASSIST_KEY_CONTENT = "content"; private static final String TAG = "TaskOverlayFactoryGo"; // Empty constructor required for ResourceBasedOverride @@ -68,8 +71,6 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { * @param The type of View in which the overlay will be placed */ public static final class TaskOverlayGo extends TaskOverlay { - private static final String ASSIST_KEY_CONTENT = "content"; - private String mNIUPackageName; private int mTaskId; private Bundle mAssistData; @@ -95,7 +96,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { } getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); - boolean isAllowedByPolicy = thumbnail.isRealSnapshot; + boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot(); getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task)); mTaskId = task.key.id; @@ -122,7 +123,11 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { }); } - private void sendNIUIntent(String actionType) { + /** + * Creates and sends an Intent corresponding to the button that was clicked + */ + @VisibleForTesting + public void sendNIUIntent(String actionType) { Intent intent = createNIUIntent(actionType); mImageApi.shareAsDataWithExplicitIntent(/* crop */ null, intent); } @@ -178,6 +183,11 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { } } } + + @VisibleForTesting + public void setImageActionsAPI(ImageActionsApi imageActionsApi) { + mImageApi = imageActionsApi; + } } /** diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml index 34ff91df9a..c61610a438 100644 --- a/quickstep/res/layout/overview_clear_all_button.xml +++ b/quickstep/res/layout/overview_clear_all_button.xml @@ -22,5 +22,4 @@ android:layout_height="wrap_content" android:text="@string/recents_clear_all" android:textColor="?attr/workspaceTextColor" - android:textSize="14sp" - android:translationY="@dimen/task_thumbnail_half_top_margin" /> \ No newline at end of file + android:textSize="14sp" /> \ No newline at end of file diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml index 0f9a6aad6f..7e5b85c41d 100644 --- a/quickstep/res/layout/task.xml +++ b/quickstep/res/layout/task.xml @@ -13,6 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. --> + + android:layout_height="match_parent"/> 24dp + + 8dp \ No newline at end of file diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 755bce8612..3036341dae 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -15,11 +15,8 @@ --> - - 80dp - 40dp 48dp - 16dp + 32dp 2dp diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index 9ab49cebfa..085db6d7b6 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -335,13 +335,17 @@ public abstract class BaseQuickstepLauncher extends Launcher ? new float[] {1, 1} : new float[] {1.1f, 0}; } + @Override + public float getNormalTaskbarScale() { + if (mTaskbarController != null) { + return mTaskbarController.getTaskbarScaleOnHome(); + } + return super.getNormalTaskbarScale(); + } + @Override public void onDragLayerHierarchyChanged() { onLauncherStateOrFocusChanged(); - - if (mTaskbarController != null) { - mTaskbarController.onLauncherDragLayerHierarchyChanged(); - } } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index fc5e2c1740..5513c1658c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -35,14 +35,13 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo private final DeviceProfile mDeviceProfile; private final LayoutInflater mLayoutInflater; private final TaskbarContainerView mTaskbarContainerView; - private final float mIconScale; public TaskbarActivityContext(BaseQuickstepLauncher launcher) { super(launcher); mDeviceProfile = launcher.getDeviceProfile().copy(this); float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size); - mIconScale = taskbarIconSize / mDeviceProfile.iconSizePx; - mDeviceProfile.updateIconSize(mIconScale, getResources()); + float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx; + mDeviceProfile.updateIconSize(iconScale, getResources()); mLayoutInflater = LayoutInflater.from(this).cloneInContext(this); @@ -73,11 +72,4 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo public Rect getFolderBoundingBox() { return mTaskbarContainerView.getFolderBoundingBox(); } - - /** - * @return The ratio of taskbar icon size vs normal workspace/hotseat icon size. - */ - public float getTaskbarIconScale() { - return mIconScale; - } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java similarity index 72% rename from quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java rename to quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java index 2228ebae8f..7c54e2d6b9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java @@ -20,36 +20,38 @@ import static com.android.launcher3.LauncherState.TASKBAR; import android.animation.Animator; import com.android.launcher3.BaseQuickstepLauncher; +import com.android.launcher3.Utilities; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.QuickStepContract; /** - * Works with TaskbarController to update the TaskbarView's alpha based on LauncherState, whether - * Launcher is in the foreground, etc. + * Works with TaskbarController to update the TaskbarView's visual properties based on factors such + * as LauncherState, whether Launcher is in the foreground, etc. */ -public class TaskbarVisibilityController { +public class TaskbarAnimationController { private static final long IME_VISIBILITY_ALPHA_DURATION = 120; - private static final long FLOATING_VIEW_VISIBILITY_ALPHA_DURATION = 120; private final BaseQuickstepLauncher mLauncher; - private final TaskbarController.TaskbarVisibilityControllerCallbacks mTaskbarCallbacks; + private final TaskbarController.TaskbarAnimationControllerCallbacks mTaskbarCallbacks; // Background alpha. - private AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat( + private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat( this::onTaskbarBackgroundAlphaChanged); // Overall visibility. - private AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat( + private final AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat( this::updateVisibilityAlpha); - private AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat( - this::updateVisibilityAlpha); - private AnimatedFloat mTaskbarVisibilityAlphaForFloatingView = new AnimatedFloat( + private final AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat( this::updateVisibilityAlpha); - public TaskbarVisibilityController(BaseQuickstepLauncher launcher, - TaskbarController.TaskbarVisibilityControllerCallbacks taskbarCallbacks) { + // Scale. + private final AnimatedFloat mTaskbarScaleForLauncherState = new AnimatedFloat( + this::updateScale); + + public TaskbarAnimationController(BaseQuickstepLauncher launcher, + TaskbarController.TaskbarAnimationControllerCallbacks taskbarCallbacks) { mLauncher = launcher; mTaskbarCallbacks = taskbarCallbacks; } @@ -62,7 +64,6 @@ public class TaskbarVisibilityController { boolean isImeVisible = (SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags() & QuickStepContract.SYSUI_STATE_IME_SHOWING) != 0; mTaskbarVisibilityAlphaForIme.updateValue(isImeVisible ? 0f : 1f); - mTaskbarVisibilityAlphaForFloatingView.updateValue(1f); onTaskbarBackgroundAlphaChanged(); updateVisibilityAlpha(); @@ -76,6 +77,10 @@ public class TaskbarVisibilityController { return mTaskbarVisibilityAlphaForLauncherState; } + protected AnimatedFloat getTaskbarScaleForLauncherState() { + return mTaskbarScaleForLauncherState; + } + protected Animator createAnimToBackgroundAlpha(float toAlpha, long duration) { return mTaskbarBackgroundAlpha.animateToValue(mTaskbarBackgroundAlpha.value, toAlpha) .setDuration(duration); @@ -86,14 +91,10 @@ public class TaskbarVisibilityController { .setDuration(IME_VISIBILITY_ALPHA_DURATION).start(); } - protected void animateToVisibilityForFloatingView(float toAlpha) { - mTaskbarVisibilityAlphaForIme.animateToValue(mTaskbarVisibilityAlphaForFloatingView.value, - toAlpha).setDuration(FLOATING_VIEW_VISIBILITY_ALPHA_DURATION).start(); - } - private void onTaskbarBackgroundAlphaChanged() { mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value); updateVisibilityAlpha(); + updateScale(); } private void updateVisibilityAlpha() { @@ -102,8 +103,7 @@ public class TaskbarVisibilityController { // LauncherState if Launcher is paused. float alphaDueToLauncher = Math.max(mTaskbarBackgroundAlpha.value, mTaskbarVisibilityAlphaForLauncherState.value); - float alphaDueToOther = mTaskbarVisibilityAlphaForIme.value - * mTaskbarVisibilityAlphaForFloatingView.value; + float alphaDueToOther = mTaskbarVisibilityAlphaForIme.value; float taskbarAlpha = alphaDueToLauncher * alphaDueToOther; mTaskbarCallbacks.updateTaskbarVisibilityAlpha(taskbarAlpha); @@ -111,6 +111,15 @@ public class TaskbarVisibilityController { setNavBarButtonAlpha(1f - taskbarAlpha); } + private void updateScale() { + // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the + // assumption being that Taskbar should always be at scale 1f regardless of the current + // LauncherState if Launcher is paused. + float scale = mTaskbarScaleForLauncherState.value; + scale = Utilities.mapRange(mTaskbarBackgroundAlpha.value, scale, 1f); + mTaskbarCallbacks.updateTaskbarScale(scale); + } + private void setNavBarButtonAlpha(float navBarAlpha) { SystemUiProxy.INSTANCE.get(mLauncher).setNavBarButtonAlpha(navBarAlpha, false); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java index abf6d54146..de23ad2efa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java @@ -19,8 +19,6 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT; import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR; @@ -75,7 +73,7 @@ public class TaskbarController { // Layout width and height of the Taskbar in the default state. private final Point mTaskbarSize; private final TaskbarStateHandler mTaskbarStateHandler; - private final TaskbarVisibilityController mTaskbarVisibilityController; + private final TaskbarAnimationController mTaskbarAnimationController; private final TaskbarHotseatController mHotseatController; private final TaskbarRecentsController mRecentsController; private final TaskbarDragController mDragController; @@ -104,8 +102,8 @@ public class TaskbarController { mWindowManager = mLauncher.getWindowManager(); mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize); mTaskbarStateHandler = mLauncher.getTaskbarStateHandler(); - mTaskbarVisibilityController = new TaskbarVisibilityController(mLauncher, - createTaskbarVisibilityControllerCallbacks()); + mTaskbarAnimationController = new TaskbarAnimationController(mLauncher, + createTaskbarAnimationControllerCallbacks()); mHotseatController = new TaskbarHotseatController(mLauncher, createTaskbarHotseatControllerCallbacks()); mRecentsController = new TaskbarRecentsController(mLauncher, @@ -113,8 +111,8 @@ public class TaskbarController { mDragController = new TaskbarDragController(mLauncher); } - private TaskbarVisibilityControllerCallbacks createTaskbarVisibilityControllerCallbacks() { - return new TaskbarVisibilityControllerCallbacks() { + private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() { + return new TaskbarAnimationControllerCallbacks() { @Override public void updateTaskbarBackgroundAlpha(float alpha) { mTaskbarViewInApp.setBackgroundAlpha(alpha); @@ -125,6 +123,12 @@ public class TaskbarController { mTaskbarContainerView.setAlpha(alpha); mTaskbarViewOnHome.setAlpha(alpha); } + + @Override + public void updateTaskbarScale(float scale) { + mTaskbarViewInApp.setScaleX(scale); + mTaskbarViewInApp.setScaleY(scale); + } }; } @@ -151,13 +155,22 @@ public class TaskbarController { ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, ActivityOptions.makeBasic()); } else if (tag instanceof FolderInfo) { - if (mLauncher.hasBeenResumed()) { - FolderInfo folderInfo = (FolderInfo) tag; - onClickedOnFolderFromHome(folderInfo); - } else { - FolderIcon folderIcon = (FolderIcon) view; - onClickedOnFolderInApp(folderIcon); - } + FolderIcon folderIcon = (FolderIcon) view; + Folder folder = folderIcon.getFolder(); + + setTaskbarWindowFullscreen(true); + + mTaskbarContainerView.post(() -> { + folder.animateOpen(); + + folder.iterateOverItems((itemInfo, itemView) -> { + itemView.setOnClickListener(getItemOnClickListener()); + itemView.setOnLongClickListener(getItemOnLongClickListener()); + // To play haptic when dragging, like other Taskbar items do. + itemView.setHapticFeedbackEnabled(true); + return false; + }); + }); } else { ItemClickHandler.INSTANCE.onClick(view); } @@ -167,44 +180,9 @@ public class TaskbarController { }; } - // Open the real folder in Launcher. - private void onClickedOnFolderFromHome(FolderInfo folderInfo) { - alignRealHotseatWithTaskbar(); - - FolderIcon folderIcon = (FolderIcon) mLauncher.getHotseat() - .getFirstItemMatch((info, v) -> info == folderInfo); - folderIcon.post(folderIcon::performClick); - } - - // Open the Taskbar folder, and handle clicks on folder items. - private void onClickedOnFolderInApp(FolderIcon folderIcon) { - Folder folder = folderIcon.getFolder(); - - setTaskbarWindowFullscreen(true); - - mTaskbarContainerView.post(() -> { - folder.animateOpen(); - - folder.iterateOverItems((itemInfo, itemView) -> { - itemView.setOnClickListener(getItemOnClickListener()); - itemView.setOnLongClickListener(getItemOnLongClickListener()); - // To play haptic when dragging, like other Taskbar items do. - itemView.setHapticFeedbackEnabled(true); - return false; - }); - }); - } - @Override public View.OnLongClickListener getItemOnLongClickListener() { - return view -> { - if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) { - // TODO: remove this path - return mDragController.startWorkspaceDragOnLongClick(view); - } else { - return mDragController.startSystemDragOnLongClick(view); - } - }; + return mDragController::startSystemDragOnLongClick; } @Override @@ -268,12 +246,10 @@ public class TaskbarController { mTaskbarContainerView.init(mTaskbarViewInApp); addToWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks()); - mTaskbarVisibilityController.init(); + mTaskbarAnimationController.init(); mHotseatController.init(); mRecentsController.init(); - SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed() - ? getTaskbarScaleOnHome() : 1f); updateWhichTaskbarViewIsVisible(); } @@ -281,7 +257,12 @@ public class TaskbarController { return new TaskbarStateHandlerCallbacks() { @Override public AnimatedFloat getAlphaTarget() { - return mTaskbarVisibilityController.getTaskbarVisibilityForLauncherState(); + return mTaskbarAnimationController.getTaskbarVisibilityForLauncherState(); + } + + @Override + public AnimatedFloat getScaleTarget() { + return mTaskbarAnimationController.getTaskbarScaleForLauncherState(); } }; } @@ -300,7 +281,7 @@ public class TaskbarController { mTaskbarContainerView.cleanup(); removeFromWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(null); - mTaskbarVisibilityController.cleanup(); + mTaskbarAnimationController.cleanup(); mHotseatController.cleanup(); mRecentsController.cleanup(); } @@ -368,12 +349,10 @@ public class TaskbarController { */ public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) { PendingAnimation anim = new PendingAnimation(duration); - anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(0, duration)); + anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(0, duration)); if (toState != null) { mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim); } - anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), - getTaskbarScaleOnHome(), LINEAR); anim.addListener(new AnimatorListenerAdapter() { @Override @@ -394,8 +373,7 @@ public class TaskbarController { private Animator createAnimToApp(long duration) { PendingAnimation anim = new PendingAnimation(duration); - anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration)); - anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR); + anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(1, duration)); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { @@ -416,7 +394,7 @@ public class TaskbarController { * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly. */ public void setIsImeVisible(boolean isImeVisible) { - mTaskbarVisibilityController.animateToVisibilityForIme(isImeVisible ? 0 : 1); + mTaskbarAnimationController.animateToVisibilityForIme(isImeVisible ? 0 : 1); } /** @@ -509,14 +487,6 @@ public class TaskbarController { mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom); } - /** - * A view was added or removed from DragLayer, check if we need to hide our hotseat copy and - * show the real one instead. - */ - public void onLauncherDragLayerHierarchyChanged() { - // TODO: remove, as this is a no-op now - } - private void updateWhichTaskbarViewIsVisible() { boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher || mIsAnimatingToApp; @@ -561,15 +531,17 @@ public class TaskbarController { */ protected interface TaskbarStateHandlerCallbacks { AnimatedFloat getAlphaTarget(); + AnimatedFloat getScaleTarget(); } /** - * Contains methods that TaskbarVisibilityController can call to interface with + * Contains methods that TaskbarAnimationController can call to interface with * TaskbarController. */ - protected interface TaskbarVisibilityControllerCallbacks { + protected interface TaskbarAnimationControllerCallbacks { void updateTaskbarBackgroundAlpha(float alpha); void updateTaskbarVisibilityAlpha(float alpha); + void updateTaskbarScale(float scale); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index f51e49837d..5eb34cb360 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -33,7 +33,6 @@ import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.BubbleTextView; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; -import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ClipDescriptionCompat; @@ -125,38 +124,6 @@ public class TaskbarDragController { return false; } - /** - * Starts a drag and drop operation that controls a real Workspace (Hotseat) view. - * @param view The Taskbar item that was long clicked. - * @return Whether {@link View#startDragAndDrop} started successfully. - */ - protected boolean startWorkspaceDragOnLongClick(View view) { - View.DragShadowBuilder transparentShadowBuilder = new View.DragShadowBuilder(view) { - private static final int ARBITRARY_SHADOW_SIZE = 10; - - @Override - public void onDrawShadow(Canvas canvas) { - } - - @Override - public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { - outShadowSize.set(ARBITRARY_SHADOW_SIZE, ARBITRARY_SHADOW_SIZE); - outShadowTouchPoint.set(ARBITRARY_SHADOW_SIZE / 2, ARBITRARY_SHADOW_SIZE / 2); - } - }; - - TaskbarDragListener taskbarDragListener = new TaskbarDragListener(mLauncher, - (ItemInfo) view.getTag()); - if (view.startDragAndDrop(new ClipData("", new String[] {taskbarDragListener.getMimeType()}, - new ClipData.Item("")), - transparentShadowBuilder, null /* localState */, View.DRAG_FLAG_GLOBAL)) { - view.setOnDragListener(getDraggedViewDragListener()); - taskbarDragListener.init(mLauncher.getDragLayer()); - return true; - } - return false; - } - /** * Hide the original Taskbar item while it is being dragged. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java deleted file mode 100644 index dc27df1909..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2021 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. - */ -package com.android.launcher3.taskbar; - -import android.content.ClipDescription; -import android.graphics.Point; -import android.view.DragEvent; -import android.view.View; - -import com.android.launcher3.BaseQuickstepLauncher; -import com.android.launcher3.dragndrop.DragLayer; -import com.android.launcher3.dragndrop.DragOptions; -import com.android.launcher3.model.data.ItemInfo; - -import java.util.UUID; - -/** - * Listens to system drag and drop events initated by the Taskbar, and forwards them to Launcher's - * internal DragController to move Hotseat items. - */ -public class TaskbarDragListener implements View.OnDragListener { - - private static final String MIME_TYPE_PREFIX = "com.android.launcher3.taskbar.drag_and_drop/"; - - private final BaseQuickstepLauncher mLauncher; - private final ItemInfo mDraggedItem; - // Randomly generated id used to verify the drag event. - private final String mId; - - // Initialized in init(). - DragLayer mDragLayer; - - /** - * @param draggedItem The info of the item that was long clicked, which we will use to find - * the equivalent match on Hotseat to drag internally. - */ - public TaskbarDragListener(BaseQuickstepLauncher launcher, ItemInfo draggedItem) { - mLauncher = launcher; - mDraggedItem = draggedItem; - mId = UUID.randomUUID().toString(); - } - - protected void init(DragLayer dragLayer) { - mDragLayer = dragLayer; - mDragLayer.setOnDragListener(this); - // Temporarily disable haptics, as system will already play one when drag and drop starts. - mDragLayer.setHapticFeedbackEnabled(false); - } - - private void cleanup() { - mDragLayer.setOnDragListener(null); - mLauncher.setNextWorkspaceDragOptions(null); - mDragLayer.setHapticFeedbackEnabled(true); - } - - /** - * Returns a randomly generated id used to verify the drag event. - */ - protected String getMimeType() { - return MIME_TYPE_PREFIX + mId; - } - - @Override - public boolean onDrag(View dragLayer, DragEvent dragEvent) { - ClipDescription clipDescription = dragEvent.getClipDescription(); - if (dragEvent.getAction() == DragEvent.ACTION_DRAG_STARTED) { - if (clipDescription == null || !clipDescription.hasMimeType(getMimeType())) { - // We didn't initiate this drag, ignore. - cleanup(); - return false; - } - View hotseatView = mLauncher.getHotseat().getFirstItemMatch( - (info, view) -> info == mDraggedItem); - if (hotseatView == null) { - cleanup(); - return false; - } - DragOptions dragOptions = new DragOptions(); - dragOptions.simulatedDndStartPoint = new Point((int) dragEvent.getX(), - (int) dragEvent.getY()); - mLauncher.setNextWorkspaceDragOptions(dragOptions); - hotseatView.performLongClick(); - } else if (dragEvent.getAction() == DragEvent.ACTION_DRAG_ENDED) { - cleanup(); - } - return mLauncher.getDragController().onDragEvent(dragEvent); - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java index b4b5d8b3fe..9fc7d995a7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java @@ -16,14 +16,12 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherState.TASKBAR; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE; -import static com.android.launcher3.states.StateAnimationConfig.SKIP_TASKBAR; +import static com.android.launcher3.anim.Interpolators.LINEAR; import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; -import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.states.StateAnimationConfig; @@ -55,8 +53,10 @@ public class TaskbarStateHandler implements StateManager.StateHandler mControllerCallbacks.onItemPositionsChanged(this)); - setLayoutTransition(mLayoutTransition); - mHotseatStartIndex = 0; mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1; updateHotseatItems(new ItemInfo[numHotseatIcons]); @@ -135,6 +130,14 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa mRecentsStartIndex = dividerIndex + 1; mRecentsEndIndex = mRecentsStartIndex + numRecentIcons - 1; updateRecentTasks(new Task[numRecentIcons]); + + mLayoutTransition = new LayoutTransition(); + addUpdateListenerForAllLayoutTransitions(() -> { + if (getLayoutTransition() == mLayoutTransition) { + mControllerCallbacks.onItemPositionsChanged(this); + } + }); + setLayoutTransition(mLayoutTransition); } private void addUpdateListenerForAllLayoutTransitions(Runnable onUpdate) { @@ -159,10 +162,20 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } protected void cleanup() { + endAllLayoutTransitionAnimators(); + setLayoutTransition(null); removeAllViews(); mHotseatRecentsDivider = null; } + private void endAllLayoutTransitionAnimators() { + mLayoutTransition.getAnimator(LayoutTransition.CHANGE_APPEARING).end(); + mLayoutTransition.getAnimator(LayoutTransition.CHANGE_DISAPPEARING).end(); + mLayoutTransition.getAnimator(LayoutTransition.CHANGING).end(); + mLayoutTransition.getAnimator(LayoutTransition.APPEARING).end(); + mLayoutTransition.getAnimator(LayoutTransition.DISAPPEARING).end(); + } + /** * Sets the alpha of the background color behind all the Taskbar contents. * @param alpha 0 is fully transparent, 1 is fully opaque. diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index d8a5f9bdfe..43e70a3923 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -82,6 +82,11 @@ public class OverviewState extends LauncherState { return new float[] {NO_SCALE, NO_OFFSET}; } + @Override + public float getTaskbarScale(Launcher launcher) { + return 1f; + } + @Override public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) { return new PageAlphaProvider(DEACCEL_2) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java index 473fe2d989..de7be5dbb8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -18,7 +18,6 @@ package com.android.launcher3.uioverrides.states; import static android.view.View.VISIBLE; import static com.android.launcher3.LauncherState.HINT_STATE; -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.WorkspaceStateTransitionAnimation.getSpringScaleAnimator; @@ -33,12 +32,10 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.launcher3.anim.Interpolators.clampToProgress; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; @@ -82,7 +79,6 @@ public class QuickstepAtomicAnimationFactory extends if (toState == NORMAL && fromState == OVERVIEW) { config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL); config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL); - config.setInterpolator(ANIM_TASKBAR_FADE, ACCEL); config.setInterpolator(ANIM_ALL_APPS_FADE, ACCEL); config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f)); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL_DEACCEL); @@ -141,7 +137,6 @@ public class QuickstepAtomicAnimationFactory extends config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_2); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, OVERSHOOT_1_2); - config.setInterpolator(ANIM_TASKBAR_FADE, OVERSHOOT_1_2); } else if (fromState == HINT_STATE && toState == NORMAL) { config.setInterpolator(ANIM_DEPTH, DEACCEL_3); if (mHintToNormalDuration == -1) { @@ -150,17 +145,6 @@ public class QuickstepAtomicAnimationFactory extends mHintToNormalDuration = (int) va.getDuration(); } config.duration = Math.max(config.duration, mHintToNormalDuration); - } else if (mActivity.getTaskbarController() != null) { - boolean wasHotseatVisible = fromState.areElementsVisible(mActivity, HOTSEAT_ICONS); - boolean isHotseatVisible = toState.areElementsVisible(mActivity, HOTSEAT_ICONS); - if (wasHotseatVisible || isHotseatVisible) { - config.setInterpolator(ANIM_TASKBAR_FADE, INSTANT); - config.setInterpolator(ANIM_HOTSEAT_FADE, INSTANT); - - if (isHotseatVisible) { - mActivity.getTaskbarController().alignRealHotseatWithTaskbar(); - } - } } } } diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index b49282544d..1a5f9c221e 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -22,7 +22,6 @@ import static android.widget.Toast.LENGTH_SHORT; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; -import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; @@ -97,11 +96,12 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.InputConsumerProxy; +import com.android.quickstep.util.InputProxyHandlerFactory; import com.android.quickstep.util.MotionPauseDetector; -import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.ProtoTracer; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.SwipePipToHomeAnimator; import com.android.quickstep.util.TransformParams; @@ -113,12 +113,10 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.LatencyTrackerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.TaskInfoCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; -import java.util.Arrays; import java.util.function.Consumer; /** @@ -200,7 +198,7 @@ public abstract class AbsSwipeUpHandler, STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED; public static final long MAX_SWIPE_DURATION = 350; - public static final long MIN_OVERSHOOT_DURATION = 120; + public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS; public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f; private static final float SWIPE_DURATION_MULTIPLIER = @@ -255,7 +253,10 @@ public abstract class AbsSwipeUpHandler, mActivityInterface = gestureState.getActivityInterface(); mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit); mInputConsumerProxy = - new InputConsumerProxy(inputConsumer, this::createNewInputProxyHandler); + new InputConsumerProxy(inputConsumer, () -> { + endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); + endLauncherTransitionController(); + }, new InputProxyHandlerFactory(mActivityInterface, mGestureState)); mTaskAnimationManager = taskAnimationManager; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; @@ -783,19 +784,6 @@ public abstract class AbsSwipeUpHandler, handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */); } - /** - * Called to create a input proxy for the running task - */ - @UiThread - protected InputConsumer createNewInputProxyHandler() { - endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); - endLauncherTransitionController(); - - StatefulActivity activity = mActivityInterface.getCreatedActivity(); - return activity == null ? InputConsumer.NO_OP - : new OverviewInputConsumer(mGestureState, activity, null, true); - } - private void endRunningWindowAnim(boolean cancel) { if (mRunningWindowAnim != null) { if (cancel) { @@ -923,6 +911,9 @@ public abstract class AbsSwipeUpHandler, float currentShift = mCurrentShift.value; final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity, isFling, isCancel); + // Set the state, but don't notify until the animation completes + mGestureState.setEndTarget(endTarget, false /* isAtomic */); + float endShift = endTarget.isLauncher ? 1 : 0; final float startShift; if (!isFling) { @@ -945,7 +936,7 @@ public abstract class AbsSwipeUpHandler, } Interpolator interpolator; S state = mActivityInterface.stateFromGestureEndTarget(endTarget); - if (state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) { + if (state.displayOverviewTasksAsGrid(mDp)) { interpolator = ACCEL_DEACCEL; } else if (endTarget == RECENTS) { interpolator = OVERSHOOT_1_2; @@ -957,7 +948,7 @@ public abstract class AbsSwipeUpHandler, mInputConsumerProxy.enable(); } if (endTarget == HOME) { - duration = Math.max(MIN_OVERSHOOT_DURATION, duration); + duration = HOME_DURATION; } else if (endTarget == RECENTS) { if (mRecentsView != null) { int nearestPage = mRecentsView.getDestinationPage(); @@ -1055,8 +1046,6 @@ public abstract class AbsSwipeUpHandler, @UiThread private void animateToProgressInternal(float start, float end, long duration, Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) { - // Set the state, but don't notify until the animation completes - mGestureState.setEndTarget(target, false /* isAtomic */); maybeUpdateRecentsAttachedState(); // If we are transitioning to launcher, then listen for the activity to be restarted while @@ -1147,10 +1136,8 @@ public abstract class AbsSwipeUpHandler, }); animatorSet.play(windowAnim); S state = mActivityInterface.stateFromGestureEndTarget(mGestureState.getEndTarget()); - if (mRecentsView != null && state.displayOverviewTasksAsGrid( - mActivity.getDeviceProfile())) { + if (mRecentsView != null && state.displayOverviewTasksAsGrid(mDp)) { animatorSet.play(ObjectAnimator.ofFloat(mRecentsView, RECENTS_GRID_PROGRESS, 1)); - animatorSet.play(mTaskViewSimulator.gridProgress.animateToValue(0, 1)); } animatorSet.setDuration(duration).setInterpolator(interpolator); animatorSet.start(); @@ -1339,6 +1326,7 @@ public abstract class AbsSwipeUpHandler, mInputConsumerProxy.destroy(); mTaskAnimationManager.setLiveTileCleanUpHandler(null); } + mInputConsumerProxy.unregisterCallback(); endRunningWindowAnim(false /* cancel */); if (mGestureEndCallback != null) { @@ -1503,36 +1491,13 @@ public abstract class AbsSwipeUpHandler, protected abstract void finishRecentsControllerToHome(Runnable callback); - private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() { - @Override - public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, - boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { - if (mRecentsView.getRunningTaskIndex() != -1 - && mRecentsView.getRunningTaskId() == task.taskId - && mRecentsAnimationTargets.hasTask(task.taskId)) { - launchOtherTaskInLiveTileMode(task.taskId, mRecentsAnimationTargets.apps); - } - ActivityManagerWrapper.getInstance().unregisterTaskStackListener( - mLiveTileRestartListener); - } - }; - private void setupLauncherUiAfterSwipeUpToRecentsAnimation() { endLauncherTransitionController(); mActivityInterface.onSwipeUpToRecentsComplete(); mRecentsView.onSwipeUpAnimationSuccess(); if (LIVE_TILE.get()) { - mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler( - appearedTaskTarget -> { - RemoteAnimationTargetCompat[] apps = Arrays.copyOf( - mRecentsAnimationTargets.apps, - mRecentsAnimationTargets.apps.length + 1); - apps[apps.length - 1] = appearedTaskTarget; - launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps); - }); mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy); - ActivityManagerWrapper.getInstance().registerTaskStackListener( - mLiveTileRestartListener); + mTaskAnimationManager.enableLiveTileRestartListener(); } SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG); @@ -1540,65 +1505,6 @@ public abstract class AbsSwipeUpHandler, reset(); } - private void launchOtherTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) { - AnimatorSet anim = new AnimatorSet(); - TaskView taskView = mRecentsView.getTaskView(taskId); - if (taskView == null || !mRecentsView.isTaskViewVisible(taskView)) { - // TODO: Refine this animation. - SurfaceTransactionApplier surfaceApplier = - new SurfaceTransactionApplier(mActivity.getDragLayer()); - ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); - appAnimator.setDuration(RECENTS_LAUNCH_DURATION); - appAnimator.setInterpolator(ACCEL_DEACCEL); - appAnimator.addUpdateListener(new MultiValueUpdateListener() { - @Override - public void onUpdate(float percent) { - SurfaceParams.Builder builder = new SurfaceParams.Builder( - apps[apps.length - 1].leash); - Matrix matrix = new Matrix(); - matrix.postScale(percent, percent); - matrix.postTranslate(mDp.widthPx * (1 - percent) / 2, - mDp.heightPx * (1 - percent) / 2); - builder.withAlpha(percent).withMatrix(matrix); - surfaceApplier.scheduleApply(builder.build()); - } - }); - anim.play(appAnimator); - } else { - TaskViewUtils.composeRecentsLaunchAnimator( - anim, taskView, apps, - mRecentsAnimationTargets.wallpapers, true /* launcherClosing */, - mActivity.getStateManager(), mRecentsView, - mActivityInterface.getDepthController()); - } - anim.addListener(new AnimatorListenerAdapter(){ - - @Override - public void onAnimationEnd(Animator animator) { - cleanUp(false); - } - - @Override - public void onAnimationCancel(Animator animator) { - cleanUp(true); - } - - private void cleanUp(boolean canceled) { - if (mRecentsAnimationController != null) { - mRecentsAnimationController.finish(false /* toRecents */, - null /* onFinishComplete */); - if (canceled) { - mRecentsAnimationController = null; - } else { - mActivityInterface.onLaunchTaskSuccess(); - } - ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); - } - } - }); - anim.start(); - } - private static boolean isNotInRecents(RemoteAnimationTargetCompat app) { return app.isNotInRecents || app.activityType == ACTIVITY_TYPE_HOME; diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 5942b3aaf4..0415009faf 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -31,6 +31,7 @@ import android.animation.Animator; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; +import android.graphics.PointF; import android.graphics.Rect; import android.os.Build; import android.view.Gravity; @@ -43,6 +44,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; @@ -195,41 +197,53 @@ public abstract class BaseActivityInterface mLaunchOtherTaskHandler; private Runnable mLiveTileCleanUpHandler; private Context mCtx; + private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() { + @Override + public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, + boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { + BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); + if (LIVE_TILE.get() && activityInterface.isInLiveTileMode() + && activityInterface.getCreatedActivity() != null) { + RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel(); + recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId); + ActivityManagerWrapper.getInstance().unregisterTaskStackListener( + mLiveTileRestartListener); + } + } + }; + TaskAnimationManager(Context ctx) { mCtx = ctx; } @@ -114,9 +129,14 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn @Override public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) { - if (mLaunchOtherTaskHandler != null - && mLastGestureState.getEndTarget() == RECENTS) { - mLaunchOtherTaskHandler.accept(appearedTaskTarget); + BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); + if (LIVE_TILE.get() && activityInterface.isInLiveTileMode() + && activityInterface.getCreatedActivity() != null) { + RecentsView recentsView = + activityInterface.getCreatedActivity().getOverviewPanel(); + RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1]; + apps[0] = appearedTaskTarget; + recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps); return; } if (mController != null) { @@ -161,17 +181,12 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn return mCallbacks; } - /** - * The passed-in handler is used to render side task launch animation in recents in live tile - * mode. - */ - public void setLaunchOtherTaskInLiveTileModeHandler( - Consumer handler) { - mLaunchOtherTaskHandler = handler; + public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) { + mLiveTileCleanUpHandler = cleanUpHandler; } - public void setLiveTileCleanUpHandler(Runnable runnable) { - mLiveTileCleanUpHandler = runnable; + public void enableLiveTileRestartListener() { + ActivityManagerWrapper.getInstance().registerTaskStackListener(mLiveTileRestartListener); } /** @@ -215,6 +230,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mLiveTileCleanUpHandler.run(); mLiveTileCleanUpHandler = null; } + ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mLiveTileRestartListener); // Release all the target leashes if (mTargets != null) { @@ -231,7 +247,6 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mTargets = null; mLastGestureState = null; mLastAppearedTaskTarget = null; - mLaunchOtherTaskHandler = null; } public void dump() { diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java index cd13200352..1ad5f2c60b 100644 --- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -176,7 +176,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride { if (thumbnail != null) { getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); - boolean isAllowedByPolicy = thumbnail.isRealSnapshot; + boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot(); getActionsView().setCallbacks(new OverlayUICallbacksImpl(isAllowedByPolicy, task)); } } diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 7a428ce637..79db842c0d 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -22,6 +22,7 @@ import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DU import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; +import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.clampToProgress; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.statehandlers.DepthController.DEPTH; @@ -200,8 +201,7 @@ public final class TaskViewUtils { tsv.setPreview(targets.apps[targets.apps.length - 1]); tsv.fullScreenProgress.value = 0; tsv.recentsViewScale.value = 1; - tsv.gridProgress.value = gridProgress; - tsv.gridTranslationSecondary.value = gridTranslationSecondary; + tsv.taskSecondaryTranslation.value = gridTranslationSecondary; tsv.setScroll(startScroll); // Fade in the task during the initial 20% of the animation @@ -214,7 +214,8 @@ public final class TaskViewUtils { AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR); out.setFloat(tsv.recentsViewScale, AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR); - out.setFloat(tsv.gridProgress, AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR); + out.setFloat(tsv.taskSecondaryTranslation, AnimatedFloat.VALUE, 0, + TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL); out.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR); TaskViewSimulator finalTsv = tsv; diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java index 3e87f48f02..2e5b33ae24 100644 --- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java +++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java @@ -38,7 +38,8 @@ public class InputConsumerProxy { private static final String TAG = "InputConsumerProxy"; private final InputConsumerController mInputConsumerController; - private final Supplier mConsumerSupplier; + private Runnable mCallback; + private Supplier mConsumerSupplier; // The consumer is created lazily on demand. private InputConsumer mInputConsumer; @@ -48,8 +49,9 @@ public class InputConsumerProxy { private boolean mDestroyPending = false; public InputConsumerProxy(InputConsumerController inputConsumerController, - Supplier consumerSupplier) { + Runnable callback, Supplier consumerSupplier) { mInputConsumerController = inputConsumerController; + mCallback = callback; mConsumerSupplier = consumerSupplier; } @@ -64,9 +66,7 @@ public class InputConsumerProxy { if (ev instanceof MotionEvent) { onInputConsumerMotionEvent((MotionEvent) ev); } else if (ev instanceof KeyEvent) { - if (mInputConsumer == null) { - mInputConsumer = mConsumerSupplier.get(); - } + initInputConsumerIfNeeded(); mInputConsumer.onKeyEvent((KeyEvent) ev); return true; } @@ -89,9 +89,7 @@ public class InputConsumerProxy { if (action == ACTION_DOWN) { mTouchInProgress = true; - if (mInputConsumer == null) { - mInputConsumer = mConsumerSupplier.get(); - } + initInputConsumerIfNeeded(); } else if (action == ACTION_CANCEL || action == ACTION_UP) { // Finish any pending actions mTouchInProgress = false; @@ -115,4 +113,18 @@ public class InputConsumerProxy { mDestroyed = true; mInputConsumerController.setInputListener(null); } + + public void unregisterCallback() { + mCallback = null; + } + + private void initInputConsumerIfNeeded() { + if (mInputConsumer == null) { + if (mCallback != null) { + mCallback.run(); + } + mInputConsumer = mConsumerSupplier.get(); + mConsumerSupplier = null; + } + } } diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java new file mode 100644 index 0000000000..8209c09304 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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. + */ +package com.android.quickstep.util; + +import androidx.annotation.UiThread; + +import com.android.launcher3.statemanager.StatefulActivity; +import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.GestureState; +import com.android.quickstep.InputConsumer; +import com.android.quickstep.inputconsumers.OverviewInputConsumer; + +import java.util.function.Supplier; + +/** + * A factory that creates a input consumer for + * {@link com.android.quickstep.util.InputConsumerProxy}. + */ +public class InputProxyHandlerFactory implements Supplier { + + private final BaseActivityInterface mActivityInterface; + private final GestureState mGestureState; + + @UiThread + public InputProxyHandlerFactory(BaseActivityInterface activityInterface, + GestureState gestureState) { + mActivityInterface = activityInterface; + mGestureState = gestureState; + } + + /** + * Called to create a input proxy for the running task + */ + @Override + public InputConsumer get() { + StatefulActivity activity = mActivityInterface.getCreatedActivity(); + return activity == null ? InputConsumer.NO_OP + : new OverviewInputConsumer(mGestureState, activity, null, true); + } +} diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index ce0ad77da3..f68e936f7f 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -24,7 +24,6 @@ import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS; import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER; import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; -import static com.android.launcher3.states.StateAnimationConfig.SKIP_TASKBAR; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -61,7 +60,10 @@ import com.android.systemui.plugins.ResourceProvider; public class StaggeredWorkspaceAnim { private static final int APP_CLOSE_ROW_START_DELAY_MS = 10; + // How long it takes to fade in each staggered row. private static final int ALPHA_DURATION_MS = 250; + // Should be used for animations running alongside this StaggeredWorkspaceAnim. + public static final int DURATION_MS = 250; private static final float MAX_VELOCITY_PX_PER_S = 22f; @@ -132,15 +134,15 @@ public class StaggeredWorkspaceAnim { } if (animateOverviewScrim) { - PendingAnimation pendingAnimation = new PendingAnimation(ALPHA_DURATION_MS); + PendingAnimation pendingAnimation = new PendingAnimation(DURATION_MS); addScrimAnimationForState(launcher, NORMAL, pendingAnimation); mAnimators.play(pendingAnimation.buildAnim()); } - addDepthAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS); + addDepthAnimationForState(launcher, NORMAL, DURATION_MS); mAnimators.play(launcher.getDragLayer().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f) - .setDuration(ALPHA_DURATION_MS)); + .setDuration(DURATION_MS)); mAnimators.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -182,8 +184,7 @@ public class StaggeredWorkspaceAnim { */ private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) { StateAnimationConfig config = new StateAnimationConfig(); - config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER - | SKIP_TASKBAR; + config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER; config.duration = 0; // setRecentsAttachedToAppWindow() will animate recents out. launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start(); diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 8b5d4989a4..6cfe3029d8 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -15,7 +15,6 @@ */ package com.android.quickstep.util; -import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.states.RotationHelper.deltaRotation; import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE; import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE; @@ -36,7 +35,6 @@ import android.util.IntProperty; import androidx.annotation.NonNull; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.touch.PagedOrientationHandler; @@ -79,7 +77,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private final boolean mIsRecentsRtl; private final Rect mTaskRect = new Rect(); - private final Rect mGridRect = new Rect(); private boolean mDrawsBelowRecents; private final PointF mPivot = new PointF(); private DeviceProfile mDp; @@ -98,22 +95,18 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private final FullscreenDrawParams mCurrentFullscreenParams; public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat(); public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat(); - public final AnimatedFloat gridTranslationSecondary = new AnimatedFloat(); // RecentsView properties public final AnimatedFloat recentsViewScale = new AnimatedFloat(); public final AnimatedFloat fullScreenProgress = new AnimatedFloat(); public final AnimatedFloat recentsViewSecondaryTranslation = new AnimatedFloat(); public final AnimatedFloat recentsViewPrimaryTranslation = new AnimatedFloat(); - public final AnimatedFloat gridProgress = new AnimatedFloat(); private final ScrollState mScrollState = new ScrollState(); // Cached calculations private boolean mLayoutValid = false; private boolean mScrollValid = false; private int mOrientationStateId; - private final int mTaskThumbnailPadding; - private final int mRowSpacing; public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) { mContext = context; @@ -125,8 +118,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mOrientationStateId = mOrientationState.getStateId(); Resources resources = context.getResources(); mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources); - mTaskThumbnailPadding = (int) resources.getDimension(R.dimen.task_thumbnail_top_margin); - mRowSpacing = (int) resources.getDimension(R.dimen.overview_grid_row_spacing); } /** @@ -268,7 +259,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mOrientationStateId = mOrientationState.getStateId(); getFullScreenScale(); - mSizeStrategy.calculateGridSize(mContext, mDp, mGridRect); mThumbnailData.rotation = mOrientationState.getDisplayRotation(); // mIsRecentsRtl is the inverse of TaskView RTL. @@ -309,34 +299,6 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mMatrix.postTranslate(insets.left, insets.top); mMatrix.postScale(scale, scale); - // Apply TaskView matrix: gridProgress related properties - float interpolatedGridProgress = ACCEL_DEACCEL.getInterpolation(gridProgress.value); - final int boxLength = (int) Math.max(taskWidth, taskHeight); - float availableHeight = mGridRect.height(); - float rowHeight = (availableHeight - mRowSpacing) / 2; - float gridScale = rowHeight / (boxLength + mTaskThumbnailPadding); - scale = Utilities.mapRange(interpolatedGridProgress, 1f, gridScale); - mMatrix.postScale(scale, scale, mIsRecentsRtl ? 0 : taskWidth, 0); - mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE, - Utilities.mapRange(interpolatedGridProgress, 0, gridTranslationSecondary.value)); - - // Apply TaskView matrix: task rect and grid rect difference - float scaledWidth = taskWidth * gridScale; - float taskGridHorizontalDiff; - if (mIsRecentsRtl) { - float taskRight = mTaskRect.left + scaledWidth; - taskGridHorizontalDiff = mGridRect.right - taskRight; - } else { - float taskLeft = mTaskRect.right - scaledWidth; - taskGridHorizontalDiff = mGridRect.left - taskLeft; - } - float taskGridVerticalDiff = - mGridRect.top + mTaskThumbnailPadding * gridScale - mTaskRect.top; - mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE, - Utilities.mapRange(interpolatedGridProgress, 0, taskGridHorizontalDiff)); - mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE, - Utilities.mapRange(interpolatedGridProgress, 0, taskGridVerticalDiff)); - // Apply TaskView matrix: translate, scroll mMatrix.postTranslate(mTaskRect.left, mTaskRect.top); mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE, diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java index e7101ccfe9..12b59d0817 100644 --- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java +++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java @@ -21,6 +21,7 @@ import android.util.AttributeSet; import android.util.FloatProperty; import android.widget.Button; +import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.views.RecentsView.ScrollState; @@ -40,30 +41,32 @@ public class ClearAllButton extends Button implements PageCallbacks { } }; + private final StatefulActivity mActivity; private float mScrollAlpha = 1; private float mContentAlpha = 1; private float mVisibilityAlpha = 1; private float mGridProgress = 1; private boolean mIsRtl; - private final float mOriginalTranslationX, mOriginalTranslationY; private float mNormalTranslationPrimary; private float mGridTranslationPrimary; + private float mGridTranslationSecondary; + private float mGridScrollOffset; + private float mOffsetTranslationPrimary; - private int mScrollOffset; + private int mSidePadding; public ClearAllButton(Context context, AttributeSet attrs) { super(context, attrs); mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; - mOriginalTranslationX = getTranslationX(); - mOriginalTranslationY = getTranslationY(); + mActivity = StatefulActivity.fromContext(context); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler(); - mScrollOffset = orientationHandler.getClearAllScrollOffset(getRecentsView(), mIsRtl); + mSidePadding = orientationHandler.getClearAllSidePadding(getRecentsView(), mIsRtl); } private RecentsView getRecentsView() { @@ -96,25 +99,27 @@ public class ClearAllButton extends Button implements PageCallbacks { } @Override - public void onPageScroll(ScrollState scrollState) { - PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler(); + public void onPageScroll(ScrollState scrollState, boolean gridEnabled) { + RecentsView recentsView = getRecentsView(); + if (recentsView == null) { + return; + } + + PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler(); float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight()); if (orientationSize == 0) { return; } - float shift; - if (mIsRtl) { - shift = Math.min(scrollState.scrollFromEdge, orientationSize); - } else { - shift = Math.min(scrollState.scrollFromEdge, - orientationSize + getGridTrans(mGridTranslationPrimary)) - - getGridTrans(mGridTranslationPrimary); + int leftEdgeScroll = recentsView.getLeftMostChildScroll(); + float adjustedScrollFromEdge = scrollState.scrollFromEdge - leftEdgeScroll; + float shift = Math.min(adjustedScrollFromEdge, orientationSize); + mNormalTranslationPrimary = mIsRtl ? -shift : shift; + if (!gridEnabled) { + mNormalTranslationPrimary += mSidePadding; } - mNormalTranslationPrimary = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift); applyPrimaryTranslation(); - orientationHandler.getSecondaryViewTranslate().set(this, - orientationHandler.getSecondaryValue(mOriginalTranslationX, mOriginalTranslationY)); + applySecondaryTranslation(); mScrollAlpha = 1 - shift / orientationSize; updateAlpha(); } @@ -130,11 +135,26 @@ public class ClearAllButton extends Button implements PageCallbacks { applyPrimaryTranslation(); } + public void setGridTranslationSecondary(float gridTranslationSecondary) { + mGridTranslationSecondary = gridTranslationSecondary; + applyPrimaryTranslation(); + } + + public void setGridScrollOffset(float gridScrollOffset) { + mGridScrollOffset = gridScrollOffset; + } + + public void setOffsetTranslationPrimary(float offsetTranslationPrimary) { + mOffsetTranslationPrimary = offsetTranslationPrimary; + applyPrimaryTranslation(); + } + public float getScrollAdjustment(boolean gridEnabled) { float scrollAdjustment = 0; if (gridEnabled) { - scrollAdjustment += mGridTranslationPrimary; + scrollAdjustment += mGridTranslationPrimary + mGridScrollOffset; } + scrollAdjustment += mOffsetTranslationPrimary; return scrollAdjustment; } @@ -160,10 +180,31 @@ public class ClearAllButton extends Button implements PageCallbacks { PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler(); orientationHandler.getPrimaryViewTranslate().set(this, - mNormalTranslationPrimary + getGridTrans(mGridTranslationPrimary)); + orientationHandler.getPrimaryValue(0f, getOriginalTranslationY()) + + mNormalTranslationPrimary + mOffsetTranslationPrimary + getGridTrans( + mGridTranslationPrimary)); + } + + private void applySecondaryTranslation() { + RecentsView recentsView = getRecentsView(); + if (recentsView == null) { + return; + } + + PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler(); + orientationHandler.getSecondaryViewTranslate().set(this, + orientationHandler.getSecondaryValue(0f, getOriginalTranslationY()) + + getGridTrans(mGridTranslationSecondary)); } private float getGridTrans(float endTranslation) { return mGridProgress > 0 ? endTranslation : 0; } + + /** + * Get the Y translation that is set in the original layout position, before scrolling. + */ + private float getOriginalTranslationY() { + return mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx / 2.0f; + } } diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 1241982040..6fcd54cf62 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -29,6 +29,7 @@ import android.widget.FrameLayout; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.util.MultiValueAlpha; @@ -144,6 +145,7 @@ public class OverviewActionsView extends FrameLayo public void setInsets(Rect insets) { mInsets.set(insets); updateVerticalMargin(SysUINavigationMode.getMode(getContext())); + updateHorizontalPadding(); } public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) { @@ -187,6 +189,10 @@ public class OverviewActionsView extends FrameLayo return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA); } + private void updateHorizontalPadding() { + setPadding(mInsets.left, 0, mInsets.right, 0); + } + /** Updates vertical margins for different navigation mode or configuration changes. */ public void updateVerticalMargin(Mode mode) { LayoutParams actionParams = (LayoutParams) findViewById( @@ -196,6 +202,13 @@ public class OverviewActionsView extends FrameLayo getBottomVerticalMargin(mode)); } + /** + * Set the device profile for this view to draw with. + */ + public void setDp(DeviceProfile dp) { + requestLayout(); + } + protected int getBottomVerticalMargin(Mode mode) { int bottomMargin; int orientation = getResources().getConfiguration().orientation; diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 4d8176c7e5..769344080a 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -27,6 +27,7 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; +import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.mapToRange; import static com.android.launcher3.Utilities.squaredHypot; @@ -34,6 +35,7 @@ import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; import static com.android.launcher3.anim.Interpolators.ACCEL_2; +import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL; @@ -50,6 +52,7 @@ import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS; import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.LayoutTransition; import android.animation.LayoutTransition.TransitionListener; @@ -61,6 +64,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -129,8 +133,11 @@ import com.android.quickstep.RecentsModel.TaskVisualsChangeListener; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskThumbnailCache; +import com.android.quickstep.TaskViewUtils; import com.android.quickstep.ViewUtils; +import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.LayoutUtils; +import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.SplitScreenBounds; import com.android.quickstep.util.SurfaceTransactionApplier; @@ -142,6 +149,8 @@ import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.PackageManagerWrapper; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.wm.shell.pip.IPipAnimationListener; @@ -301,6 +310,7 @@ public abstract class RecentsView extends PagedView protected final Rect mTempRect = new Rect(); protected final RectF mTempRectF = new RectF(); private final PointF mTempPointF = new PointF(); + private float mFullscreenScale; private static final int DISMISS_TASK_DURATION = 300; private static final int ADDITION_TASK_DURATION = 200; @@ -310,7 +320,6 @@ public abstract class RecentsView extends PagedView protected final T mActivity; private final float mFastFlingVelocity; private final RecentsModel mModel; - private final int mTaskTopMargin; private final int mRowSpacing; private final ClearAllButton mClearAllButton; private final Rect mClearAllButtonDeadZoneRect = new Rect(); @@ -529,8 +538,6 @@ public abstract class RecentsView extends PagedView mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources()); setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); - mTaskTopMargin = getResources() - .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); mRowSpacing = getResources().getDimensionPixelSize(R.dimen.overview_grid_row_spacing); mSquaredTouchSlop = squaredTouchSlop(context); @@ -717,6 +724,72 @@ public abstract class RecentsView extends PagedView super.draw(canvas); } + public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) { + if (mRunningTaskId != -1 && mRunningTaskId == taskId && + getLiveTileParams().getTargetSet().findTask(taskId) != null) { + launchSideTaskInLiveTileMode(taskId, getLiveTileParams().getTargetSet().apps); + } + } + + public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) { + AnimatorSet anim = new AnimatorSet(); + TaskView taskView = getTaskView(taskId); + if (taskView == null || !isTaskViewVisible(taskView)) { + // TODO: Refine this animation. + SurfaceTransactionApplier surfaceApplier = + new SurfaceTransactionApplier(mActivity.getDragLayer()); + ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); + appAnimator.setDuration(RECENTS_LAUNCH_DURATION); + appAnimator.setInterpolator(ACCEL_DEACCEL); + appAnimator.addUpdateListener(new MultiValueUpdateListener() { + @Override + public void onUpdate(float percent) { + SurfaceParams.Builder builder = new SurfaceParams.Builder( + apps[apps.length - 1].leash); + Matrix matrix = new Matrix(); + matrix.postScale(percent, percent); + matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2, + mActivity.getDeviceProfile().heightPx * (1 - percent) / 2); + builder.withAlpha(percent).withMatrix(matrix); + surfaceApplier.scheduleApply(builder.build()); + } + }); + anim.play(appAnimator); + } else { + TaskViewUtils.composeRecentsLaunchAnimator( + anim, taskView, apps, + mLiveTileParams.getTargetSet().wallpapers, true /* launcherClosing */, + mActivity.getStateManager(), this, + getDepthController()); + } + anim.addListener(new AnimatorListenerAdapter(){ + + @Override + public void onAnimationEnd(Animator animator) { + cleanUp(false); + } + + @Override + public void onAnimationCancel(Animator animator) { + cleanUp(true); + } + + private void cleanUp(boolean canceled) { + if (mRecentsAnimationController != null) { + mRecentsAnimationController.finish(false /* toRecents */, + null /* onFinishComplete */); + if (canceled) { + mRecentsAnimationController = null; + } else { + mSizeStrategy.onLaunchTaskSuccess(); + } + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); + } + } + }); + anim.start(); + } + private void updateTaskStartIndex(View affectingView) { if (!(affectingView instanceof TaskView) && !(affectingView instanceof ClearAllButton)) { int childCount = getChildCount(); @@ -744,7 +817,7 @@ public abstract class RecentsView extends PagedView int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment( mOverviewFullscreenEnabled, showAsGrid()); int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment( - mOverviewFullscreenEnabled, showAsGrid())); + mOverviewFullscreenEnabled)); int taskEnd = taskStart + taskSize; return (taskStart >= start && taskStart <= end) || (taskEnd >= start && taskEnd <= end); @@ -1022,7 +1095,6 @@ public abstract class RecentsView extends PagedView mLiveTileTaskViewSimulator.taskSecondaryTranslation.value = 0; mLiveTileTaskViewSimulator.fullScreenProgress.value = 0; mLiveTileTaskViewSimulator.recentsViewScale.value = 1; - mLiveTileTaskViewSimulator.gridProgress.value = 0; } if (mRunningTaskTileHidden) { setRunningTaskHidden(mRunningTaskTileHidden); @@ -1066,7 +1138,9 @@ public abstract class RecentsView extends PagedView public void setInsets(Rect insets) { mInsets.set(insets); resetPaddingFromTaskSize(); - mLiveTileTaskViewSimulator.setDp(mActivity.getDeviceProfile()); + DeviceProfile dp = mActivity.getDeviceProfile(); + mLiveTileTaskViewSimulator.setDp(dp); + mActionsView.setDp(dp); } private void resetPaddingFromTaskSize() { @@ -1075,7 +1149,7 @@ public abstract class RecentsView extends PagedView mTaskWidth = mTempRect.width(); mTaskHeight = mTempRect.height(); - mTempRect.top -= mTaskTopMargin; + mTempRect.top -= dp.overviewTaskThumbnailTopMarginPx; setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top, dp.widthPx - mInsets.right - mTempRect.right, dp.heightPx - mInsets.bottom - mTempRect.bottom); @@ -1092,6 +1166,10 @@ public abstract class RecentsView extends PagedView */ private void updateTaskSize() { final int taskCount = getTaskViewCount(); + if (taskCount == 0) { + return; + } + float accumulatedTranslationX = 0; float[] fullscreenTranslations = new float[taskCount]; int firstNonHomeTaskIndex = 0; @@ -1106,8 +1184,11 @@ public abstract class RecentsView extends PagedView taskView.updateTaskSize(); fullscreenTranslations[i] += accumulatedTranslationX; + // Compensate space caused by TaskView scaling. float widthDiff = taskView.getLayoutParams().width * (1 - taskView.getFullscreenScale()); + // Compensate page spacing widening caused by RecentsView scaling. + widthDiff += mPageSpacing * (1 - 1 / mFullscreenScale); float fullscreenTranslationX = mIsRtl ? widthDiff : -widthDiff; fullscreenTranslations[i] += fullscreenTranslationX; accumulatedTranslationX += fullscreenTranslationX; @@ -1181,13 +1262,13 @@ public abstract class RecentsView extends PagedView View page = getPageAt(i); mScrollState.updateInterpolation(mActivity.getDeviceProfile(), mOrientationHandler.getChildStartWithTranslation(page)); - ((PageCallbacks) page).onPageScroll(mScrollState); + ((PageCallbacks) page).onPageScroll(mScrollState, mOverviewGridEnabled); } } @Override protected int getDestinationPage(int scaledScroll) { - if (mGridProgress == 0) { + if (!showAsGrid()) { return super.getDestinationPage(scaledScroll); } @@ -1600,10 +1681,7 @@ public abstract class RecentsView extends PagedView } final int boxLength = Math.max(mTaskWidth, mTaskHeight); - float availableHeight = mLastComputedGridSize.height(); - float rowHeight = (availableHeight - mRowSpacing) / 2; - float gridScale = rowHeight / (boxLength + mTaskTopMargin); - + int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; int topRowWidth = 0; int bottomRowWidth = 0; float topAccumulatedTranslationX = 0; @@ -1621,43 +1699,17 @@ public abstract class RecentsView extends PagedView continue; } - taskView.setGridScale(gridScale); - - float scaledWidth = taskView.getLayoutParams().width * gridScale; - float taskGridHorizontalDiff; - if (mIsRtl) { - float taskRight = mLastComputedTaskSize.left + scaledWidth; - taskGridHorizontalDiff = mLastComputedGridSize.right - taskRight; - } else { - float taskLeft = mLastComputedTaskSize.right - scaledWidth; - taskGridHorizontalDiff = mLastComputedGridSize.left - taskLeft; - } - gridTranslations[i] -= taskGridHorizontalDiff; - taskView.setGridOffsetTranslationX(taskGridHorizontalDiff); - - float taskGridVerticalDiff = mLastComputedGridSize.top + mTaskTopMargin * gridScale - - mLastComputedTaskSize.top; - - // Off-set gap due to task scaling. - float widthDiff = taskView.getLayoutParams().width * (1 - gridScale); - float gridScaleTranslationX = mIsRtl ? widthDiff : -widthDiff; - gridTranslations[i] += gridScaleTranslationX; - - // Visible offset caused by having scaling pivot on top-right. - taskView.setNonRtlVisibleOffset(mIsRtl ? 0 : widthDiff); - if (topRowWidth <= bottomRowWidth) { gridTranslations[i] += topAccumulatedTranslationX; - topRowWidth += taskView.getLayoutParams().width * gridScale + mPageSpacing; + topRowWidth += taskView.getLayoutParams().width + mPageSpacing; topSet.add(i); - taskView.setGridTranslationY(taskGridVerticalDiff); + taskView.setGridTranslationY(0); // Move horizontally into empty space. float widthOffset = 0; for (int j = i - 1; bottomSet.contains(j); j--) { - widthOffset += getTaskViewAt(j).getLayoutParams().width * gridScale - + mPageSpacing; + widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing; } float gridTranslationX = mIsRtl ? widthOffset : -widthOffset; @@ -1665,26 +1717,39 @@ public abstract class RecentsView extends PagedView topAccumulatedTranslationX += gridTranslationX; } else { gridTranslations[i] += bottomAccumulatedTranslationX; - bottomRowWidth += taskView.getLayoutParams().width * gridScale + mPageSpacing; + bottomRowWidth += taskView.getLayoutParams().width + mPageSpacing; bottomSet.add(i); // Move into bottom row. - float heightOffset = (boxLength + mTaskTopMargin) * gridScale + mRowSpacing; - taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff); + float heightOffset = (boxLength + taskTopMargin) + mRowSpacing; + taskView.setGridTranslationY(heightOffset); // Move horizontally into empty space. float widthOffset = 0; for (int j = i - 1; topSet.contains(j); j--) { - widthOffset += getTaskViewAt(j).getLayoutParams().width * gridScale - + mPageSpacing; + widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing; } float gridTranslationX = mIsRtl ? widthOffset : -widthOffset; gridTranslations[i] += gridTranslationX; bottomAccumulatedTranslationX += gridTranslationX; } - topAccumulatedTranslationX += gridScaleTranslationX; - bottomAccumulatedTranslationX += gridScaleTranslationX; + } + + // If the first non-home task does not take full width of task Rect, shift all tasks + // accordingly without affecting scrolls. + int firstTaskWidth = getTaskViewAt(firstNonHomeTaskIndex).getLayoutParams().width; + float firstNonHomeTaskOffset = firstTaskWidth == ViewGroup.LayoutParams.MATCH_PARENT ? 0 + : mTaskWidth - firstTaskWidth; + float offsetTranslation = mIsRtl ? firstNonHomeTaskOffset : -firstNonHomeTaskOffset; + + // We need to maintain first non-home task's grid translation at 0, now shift translation + // of all the TaskViews to achieve that. + for (int i = firstNonHomeTaskIndex; i < taskCount; i++) { + TaskView taskView = getTaskViewAt(i); + taskView.setGridTranslationX( + gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]); + taskView.setGridOffsetTranslationX(offsetTranslation); } // Use the accumulated translation of the longer row. @@ -1700,7 +1765,7 @@ public abstract class RecentsView extends PagedView shorterRowCompensation = bottomRowWidth - topRowWidth; } } else { - if (!topSet.contains(taskCount - 1)) { + if (bottomSet.contains(taskCount - 1)) { shorterRowCompensation = topRowWidth - bottomRowWidth; } } @@ -1721,14 +1786,14 @@ public abstract class RecentsView extends PagedView clearAllAccumulatedTranslation + clearAllShorterRowCompensation + clearAllShortTotalCompensation; - // We need to maintain first non-home task's grid translation at 0, now shift translation - // of all the TaskViews to achieve that. - for (int i = firstNonHomeTaskIndex; i < taskCount; i++) { - getTaskViewAt(i).setGridTranslationX( - gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]); - } mClearAllButton.setGridTranslationPrimary( clearAllTotalTranslationX - gridTranslations[firstNonHomeTaskIndex]); + mClearAllButton.setGridTranslationSecondary( + boxLength - mTaskHeight / 2f + mRowSpacing / 2f); + mClearAllButton.setGridScrollOffset( + mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left + : mLastComputedTaskSize.right - mLastComputedGridSize.right); + mClearAllButton.setOffsetTranslationPrimary(offsetTranslation); setGridProgress(mGridProgress); } @@ -1753,7 +1818,6 @@ public abstract class RecentsView extends PagedView for (int i = 0; i < taskCount; i++) { getTaskViewAt(i).setGridProgress(gridProgress); } - mLiveTileTaskViewSimulator.gridProgress.value = gridProgress; mClearAllButton.setGridProgress(gridProgress); } @@ -1801,8 +1865,10 @@ public abstract class RecentsView extends PagedView /** * Updates the page UI based on scroll params. + * + * @param gridEnabled whether Overveiw is currently showing as 2 rows grid */ - default void onPageScroll(ScrollState scrollState) {} + default void onPageScroll(ScrollState scrollState, boolean gridEnabled) {} } public static class ScrollState extends CurveProperties { @@ -2297,7 +2363,7 @@ public abstract class RecentsView extends PagedView // Update the pivots such that when the task is scaled, it fills the full page getTaskSize(mTempRect); - getPagedViewOrientedState().getFullScreenScaleAndPivot( + mFullscreenScale = getPagedViewOrientedState().getFullScreenScaleAndPivot( mTempRect, mActivity.getDeviceProfile(), mTempPointF); setPivotX(mTempPointF.x); setPivotY(mTempPointF.y); @@ -2485,7 +2551,7 @@ public abstract class RecentsView extends PagedView if (child == mSplitHiddenTaskView) { int left = newScroll[i] + getPaddingStart(); - int topMargin = mSplitHiddenTaskView.getThumbnailTopMargin(); + int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1]; mSplitHiddenTaskView.layout(left, top, left + mSplitHiddenTaskView.getWidth(), @@ -2858,22 +2924,42 @@ public abstract class RecentsView extends PagedView @Override protected int computeMinScroll() { if (getTaskViewCount() > 0) { - if (mDisallowScrollToClearAll) { + if (mIsRtl && mDisallowScrollToClearAll) { // We aren't showing the clear all button, // so use the leftmost task as the min scroll. - if (mIsRtl) { - return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1))); - } - return getScrollForPage(mTaskViewStartIndex); + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1))); } - if (mIsRtl) { - return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1); - } - return getScrollForPage(mTaskViewStartIndex); + return getLeftMostChildScroll(); } return super.computeMinScroll(); } + /** + * Returns page scroll of the left most child. + */ + public int getLeftMostChildScroll() { + if (mIsRtl) { + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1); + } + return getScrollForPage(mTaskViewStartIndex); + } + + @Override + protected int computeMaxScroll() { + if (getTaskViewCount() > 0) { + if (!mIsRtl && mDisallowScrollToClearAll) { + // We aren't showing the clear all button, + // so use the rightmost task as the min scroll. + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1))); + } + if (mIsRtl) { + return getScrollForPage(mTaskViewStartIndex); + } + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1); + } + return super.computeMaxScroll(); + } + @Override protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren, ComputePageScrollsLogic scrollLogic) { @@ -2919,26 +3005,7 @@ public abstract class RecentsView extends PagedView return super.getChildVisibleSize(index); } return (int) (super.getChildVisibleSize(index) * taskView.getSizeAdjustment( - mOverviewFullscreenEnabled, showAsGrid())); - } - - @Override - protected int computeMaxScroll() { - if (getTaskViewCount() > 0) { - if (mDisallowScrollToClearAll) { - // We aren't showing the clear all button, - // so use the rightmost task as the min scroll. - if (mIsRtl) { - return getScrollForPage(mTaskViewStartIndex); - } - return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1))); - } - if (mIsRtl) { - return getScrollForPage(mTaskViewStartIndex); - } - return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1); - } - return super.computeMaxScroll(); + mOverviewFullscreenEnabled)); } public ClearAllButton getClearAllButton() { @@ -3160,7 +3227,9 @@ public abstract class RecentsView extends PagedView MAIN_EXECUTOR.execute(() -> { // Needed for activities that auto-enter PiP, which will not trigger a remote // animation to be created - mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); + if (mActivity != null) { + mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); + } }); } } diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index a5b7a5b575..a46daf38fd 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -58,7 +58,6 @@ public class TaskMenuView extends AbstractFloatingView { private static final int REVEAL_OPEN_DURATION = 150; private static final int REVEAL_CLOSE_DURATION = 100; - private final float mThumbnailTopMargin; private BaseDraggingActivity mActivity; private TextView mTaskName; private AnimatorSet mOpenCloseAnimator; @@ -73,7 +72,6 @@ public class TaskMenuView extends AbstractFloatingView { super(context, attrs, defStyleAttr); mActivity = BaseDraggingActivity.fromContext(context); - mThumbnailTopMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin); setClipToOutline(true); } @@ -123,14 +121,15 @@ public class TaskMenuView extends AbstractFloatingView { } public void setPosition(float x, float y, PagedOrientationHandler pagedOrientationHandler) { - float adjustedY = y + mThumbnailTopMargin; + int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; + float adjustedY = y + taskTopMargin; // Changing pivot to make computations easier // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set, // which would render the X and Y position set here incorrect setPivotX(0); if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) { // In tablet, set pivotY to original position without mThumbnailTopMargin adjustment. - setPivotY(-mThumbnailTopMargin); + setPivotY(-taskTopMargin); } else { setPivotY(0); } diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 2b54f95bdf..af62582418 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -440,13 +440,14 @@ public class TaskThumbnailView extends View implements PluginListener 0) { return; @@ -906,11 +906,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { return mFullscreenScale; } - public void setGridScale(float gridScale) { - mGridScale = gridScale; - applyScale(); - } - /** * Moves TaskView between carousel and 2 row grid. * @@ -927,8 +922,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { float scale = 1; float fullScreenProgress = EXAGGERATED_EASE.getInterpolation(mFullscreenProgress); scale *= Utilities.mapRange(fullScreenProgress, 1f, mFullscreenScale); - float gridProgress = ACCEL_DEACCEL.getInterpolation(mGridProgress); - scale *= Utilities.mapRange(gridProgress, 1f, mGridScale); setScaleX(scale); setScaleY(scale); } @@ -991,10 +984,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { applyTranslationX(); } - public void setNonRtlVisibleOffset(float nonRtlVisibleOffset) { - mNonRtlVisibleOffset = nonRtlVisibleOffset; - } - public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) { float scrollAdjustment = 0; if (fullscreenEnabled) { @@ -1006,22 +995,19 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { return scrollAdjustment; } - public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) { + public float getOffsetAdjustment(boolean fullscreenEnabled,boolean gridEnabled) { float offsetAdjustment = getScrollAdjustment(fullscreenEnabled, gridEnabled); if (gridEnabled) { - offsetAdjustment += mGridOffsetTranslationX + mNonRtlVisibleOffset; + offsetAdjustment += mGridOffsetTranslationX; } return offsetAdjustment; } - public float getSizeAdjustment(boolean fullscreenEnabled, boolean gridEnabled) { + public float getSizeAdjustment(boolean fullscreenEnabled) { float sizeAdjustment = 1; if (fullscreenEnabled) { sizeAdjustment *= mFullscreenScale; } - if (gridEnabled) { - sizeAdjustment *= mGridScale; - } return sizeAdjustment; } @@ -1083,17 +1069,17 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private static final class TaskOutlineProvider extends ViewOutlineProvider { - private final int mMarginTop; + private int mMarginTop; private FullscreenDrawParams mFullscreenParams; - TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams) { - mMarginTop = context.getResources().getDimensionPixelSize( - R.dimen.task_thumbnail_top_margin); + TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams, int topMargin) { + mMarginTop = topMargin; mFullscreenParams = fullscreenParams; } - public void setFullscreenParams(FullscreenDrawParams params) { + public void updateParams(FullscreenDrawParams params, int topMargin) { mFullscreenParams = params; + mMarginTop = topMargin; } @Override @@ -1216,7 +1202,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } thumbnail.setFullscreenParams(mCurrentFullscreenParams); - mOutlineProvider.setFullscreenParams(mCurrentFullscreenParams); + mOutlineProvider.updateParams( + mCurrentFullscreenParams, + mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx); invalidateOutline(); } @@ -1238,8 +1226,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { void updateTaskSize() { ViewGroup.LayoutParams params = getLayoutParams(); if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) { - final int thumbnailPadding = (int) getResources().getDimension( - R.dimen.task_thumbnail_top_margin); + final int thumbnailPadding = + mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize(); int taskWidth = lastComputedTaskSize.width(); diff --git a/res/drawable/gm_edit_24.xml b/res/drawable/gm_edit_24.xml new file mode 100644 index 0000000000..59a0dc2faf --- /dev/null +++ b/res/drawable/gm_edit_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/res/drawable/widget_reconfigure_button_frame.xml b/res/drawable/widget_reconfigure_button_frame.xml new file mode 100644 index 0000000000..37d93ade95 --- /dev/null +++ b/res/drawable/widget_reconfigure_button_frame.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml index c684881195..2accd2d21f 100644 --- a/res/layout/all_apps_tabs.xml +++ b/res/layout/all_apps_tabs.xml @@ -26,6 +26,7 @@ android:clipChildren="true" android:clipToPadding="false" android:descendantFocusability="afterDescendants" + android:paddingTop="@dimen/all_apps_header_top_padding" launcher:pageIndicator="@+id/tabs" > diff --git a/res/layout/app_widget_resize_frame.xml b/res/layout/app_widget_resize_frame.xml index 671dbc63c0..53db5edd8a 100644 --- a/res/layout/app_widget_resize_frame.xml +++ b/res/layout/app_widget_resize_frame.xml @@ -73,5 +73,17 @@ android:src="@drawable/ic_widget_resize_handle" android:tint="?android:attr/colorAccent" /> + + \ No newline at end of file diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 4078ef4092..c1c8f01a87 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -129,11 +129,10 @@ - - + @@ -170,6 +169,9 @@ + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index cf830c7ed4..1fccdf34a6 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -56,6 +56,12 @@ 24dp 22dp + + 14dp + 6dp + 32dp + 36dp + 6dp 8dp @@ -286,4 +292,9 @@ 16dp + + 0dp + 0dp + 0dp + diff --git a/res/values/strings.xml b/res/values/strings.xml index e5e5db39c4..1371e91d0f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -380,9 +380,18 @@ Work profile is paused - Work apps can\'t send you notifications, use your battery, or access your location + Work apps can’t send you notifications, use your battery, or access your location - Work profile is paused. Work apps can\’t send you notifications, use your battery, or access your location + Work profile is paused. Work apps can’t send you notifications, use your battery, or access your location + + Work apps are badged and visible to your IT admin + + Got it + + + Pause work apps + + Turn on Filter diff --git a/res/xml/size_limits.xml b/res/xml/size_limits_80x104.xml similarity index 97% rename from res/xml/size_limits.xml rename to res/xml/size_limits_80x104.xml index ba570146de..e11bc5ecfa 100644 --- a/res/xml/size_limits.xml +++ b/res/xml/size_limits_80x104.xml @@ -38,7 +38,7 @@ + launcher:c="16dp"/> ((ComponentWithLabel) invocation.getArgument(0)) diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java index 84a03d572c..12a092dafe 100644 --- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java +++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java @@ -105,7 +105,8 @@ public final class WidgetsListHeaderViewHolderBinderTest { mWidgetPreviewLoader, mIconCache, /* iconClickListener= */ view -> {}, - /* iconLongClickListener= */ view -> false); + /* iconLongClickListener= */ view -> false, + /* searchBarUIHelper= */ null); mViewHolderBinder = new WidgetsListHeaderViewHolderBinder( LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter); } diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java index 075c58db6b..e09034132c 100644 --- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java +++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java @@ -105,7 +105,8 @@ public final class WidgetsListSearchHeaderViewHolderBinderTest { mWidgetPreviewLoader, mIconCache, /* iconClickListener= */ view -> {}, - /* iconLongClickListener= */ view -> false); + /* iconLongClickListener= */ view -> false, + /* searchBarUIHelper= */ null); mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder( LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter); } diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java index 0c6e71711d..0935d1cfc4 100644 --- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java +++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java @@ -111,7 +111,8 @@ public final class WidgetsListTableViewHolderBinderTest { mWidgetPreviewLoader, mIconCache, /* iconClickListener= */ view -> {}, - /* iconLongClickListener= */ view -> false); + /* iconLongClickListener= */ view -> false, + /* searchBarUIHelper= */ null); mViewHolderBinder = new WidgetsListTableViewHolderBinder( mContext, LayoutInflater.from(mTestActivity), diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index d894bb4b82..95cdbdd147 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -98,13 +98,6 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_SNACKBAR | TYPE_WIDGET_RESIZE_FRAME | TYPE_LISTENER; - // When these types of floating views are open, hide the taskbar hotseat and show the real one. - public static final int TYPE_REPLACE_TASKBAR_WITH_HOTSEAT = TYPE_FOLDER | TYPE_ACTION_POPUP; - - // Hide the taskbar when these types of floating views are open. - public static final int TYPE_HIDE_TASKBAR = TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGETS_FULL_SHEET - | TYPE_ON_BOARD_POPUP; - public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER & ~TYPE_ALL_APPS_EDU; diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index ab9178556e..5d41bb5c3e 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -22,6 +22,7 @@ import android.util.SizeF; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.widget.ImageButton; import android.widget.ImageView; import androidx.annotation.Nullable; @@ -74,6 +75,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private LauncherAppWidgetHostView mWidgetView; private CellLayout mCellLayout; private DragLayer mDragLayer; + private ImageButton mReconfigureButton; private Rect mWidgetPadding; @@ -211,6 +213,17 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O mDragHandles[INDEX_RIGHT].setVisibility(GONE); } + mReconfigureButton = (ImageButton) findViewById(R.id.widget_reconfigure_button); + if (info.isReconfigurable()) { + mReconfigureButton.setVisibility(VISIBLE); + mReconfigureButton.setOnClickListener(view -> mLauncher + .getAppWidgetHost() + .startConfigActivity( + mLauncher, + mWidgetView.getAppWidgetId(), + Launcher.REQUEST_RECONFIGURE_APPWIDGET)); + } + // When we create the resize frame, we first mark all cells as unoccupied. The appropriate // cells (same if not resized, or different) will be marked as occupied when the resize // frame is dismissed. @@ -582,6 +595,13 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O return false; } + private boolean isTouchOnReconfigureButton(MotionEvent ev) { + int xFrame = (int) ev.getX() - getLeft(); + int yFrame = (int) ev.getY() - getTop(); + mReconfigureButton.getHitRect(sTmpRect); + return sTmpRect.contains(xFrame, yFrame); + } + @Override public boolean onControllerTouchEvent(MotionEvent ev) { int action = ev.getAction(); @@ -609,6 +629,11 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O if (ev.getAction() == MotionEvent.ACTION_DOWN && handleTouchDown(ev)) { return true; } + // Keep the resize frame open but let a click on the reconfigure button fall through to the + // button's OnClickListener. + if (isTouchOnReconfigureButton(ev)) { + return false; + } close(false); return false; } diff --git a/src/com/android/launcher3/DevicePaddings.java b/src/com/android/launcher3/DevicePaddings.java index 4827f362c8..7c387b1efe 100644 --- a/src/com/android/launcher3/DevicePaddings.java +++ b/src/com/android/launcher3/DevicePaddings.java @@ -52,8 +52,8 @@ public class DevicePaddings { ArrayList mDevicePaddings = new ArrayList<>(); - public DevicePaddings(Context context) { - try (XmlResourceParser parser = context.getResources().getXml(R.xml.size_limits)) { + public DevicePaddings(Context context, int devicePaddingId) { + try (XmlResourceParser parser = context.getResources().getXml(devicePaddingId)) { final int depth = parser.getDepth(); int type; while (((type = parser.next()) != XmlPullParser.END_TAG || @@ -94,16 +94,27 @@ public class DevicePaddings { if (workspaceTopPadding == null || workspaceBottomPadding == null || hotseatBottomPadding == null) { - throw new RuntimeException("DevicePadding missing padding."); + if (Utilities.IS_DEBUG_DEVICE) { + throw new RuntimeException("DevicePadding missing padding."); + } } - mDevicePaddings.add(new DevicePadding(maxWidthPx, workspaceTopPadding, - workspaceBottomPadding, hotseatBottomPadding)); + DevicePadding dp = new DevicePadding(maxWidthPx, workspaceTopPadding, + workspaceBottomPadding, hotseatBottomPadding); + if (dp.isValid()) { + mDevicePaddings.add(dp); + } else { + Log.e(TAG, "Invalid device padding found."); + if (Utilities.IS_DEBUG_DEVICE) { + throw new RuntimeException("DevicePadding is invalid"); + } + } } } } } } catch (IOException | XmlPullParserException e) { + Log.e(TAG, "Failure parsing device padding layout.", e); throw new RuntimeException(e); } @@ -128,6 +139,9 @@ public class DevicePaddings { */ public static final class DevicePadding { + // One for each padding since they can each be off by 1 due to rounding errors. + private static final int ROUNDING_THRESHOLD_PX = 3; + private final int maxEmptySpacePx; private final PaddingFormula workspaceTopPadding; private final PaddingFormula workspaceBottomPadding; @@ -143,6 +157,10 @@ public class DevicePaddings { this.hotseatBottomPadding = hotseatBottomPadding; } + public int getMaxEmptySpacePx() { + return maxEmptySpacePx; + } + public int getWorkspaceTopPadding(int extraSpacePx) { return workspaceTopPadding.calculate(extraSpacePx); } @@ -154,6 +172,22 @@ public class DevicePaddings { public int getHotseatBottomPadding(int extraSpacePx) { return hotseatBottomPadding.calculate(extraSpacePx); } + + public boolean isValid() { + int workspaceTopPadding = getWorkspaceTopPadding(maxEmptySpacePx); + int workspaceBottomPadding = getWorkspaceBottomPadding(maxEmptySpacePx); + int hotseatBottomPadding = getHotseatBottomPadding(maxEmptySpacePx); + int sum = workspaceTopPadding + workspaceBottomPadding + hotseatBottomPadding; + int diff = Math.abs(sum - maxEmptySpacePx); + if (DEBUG) { + Log.d(TAG, "isValid: workspaceTopPadding=" + workspaceTopPadding + + ", workspaceBottomPadding=" + workspaceBottomPadding + + ", hotseatBottomPadding=" + hotseatBottomPadding + + ", sum=" + sum + + ", diff=" + diff); + } + return diff <= ROUNDING_THRESHOLD_PX; + } } /** diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index fa19ee6918..1ce5f4dba6 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -104,6 +104,7 @@ public class DeviceProfile { private final int mWorkspacePageIndicatorOverlapWorkspace; // Workspace icons + public float iconScale; public int iconSizePx; public int iconTextSizePx; public int iconDrawablePaddingPx; @@ -151,6 +152,11 @@ public class DeviceProfile { public int allAppsIconDrawablePaddingPx; public float allAppsIconTextSizePx; + // Overview + public int overviewTaskMarginPx; + public int overviewTaskIconSizePx; + public int overviewTaskThumbnailTopMarginPx; + // Widgets public final PointF appWidgetScale = new PointF(1.0f, 1.0f); @@ -297,15 +303,29 @@ public class DeviceProfile { : (hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx + (isScalableGrid ? 0 : hotseatExtraVerticalSize))); + overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin); + overviewTaskIconSizePx = + isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get() ? res.getDimensionPixelSize( + R.dimen.task_thumbnail_icon_size_grid) : res.getDimensionPixelSize( + R.dimen.task_thumbnail_icon_size); + overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx * 2; + // Calculate all of the remaining variables. extraSpace = updateAvailableDimensions(res); // Now that we have all of the variables calculated, we can tune certain sizes. - if (isScalableGrid) { - DevicePadding padding = inv.devicePaddings.getDevicePadding(extraSpace); - workspaceTopPadding = padding.getWorkspaceTopPadding(extraSpace); - workspaceBottomPadding = padding.getWorkspaceBottomPadding(extraSpace); + if (isScalableGrid && inv.devicePaddings != null) { + // Paddings were created assuming no scaling, so we first unscale the extra space. + int unscaledExtraSpace = (int) (extraSpace / iconScale); + DevicePadding padding = inv.devicePaddings.getDevicePadding(unscaledExtraSpace); + + int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace); + int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace); + int paddingHotseatBottom = padding.getHotseatBottomPadding(unscaledExtraSpace); + + workspaceTopPadding = Math.round(paddingWorkspaceTop * iconScale); + workspaceBottomPadding = Math.round(paddingWorkspaceBottom * iconScale); + extraHotseatBottomPadding = Math.round(paddingHotseatBottom * iconScale); - extraHotseatBottomPadding = padding.getHotseatBottomPadding(extraSpace); hotseatBarSizePx += extraHotseatBottomPadding; hotseatBarBottomPaddingPx += extraHotseatBottomPadding; } else if (!isVerticalBarLayout() && isPhone && isTallDevice) { @@ -478,6 +498,8 @@ public class DeviceProfile { * hotseat sizes, workspaceSpringLoadedShrinkFactor, folderIconSizePx, and folderIconOffsetYPx. */ public void updateIconSize(float scale, Resources res) { + iconScale = scale; + // Workspace final boolean isVerticalLayout = isVerticalBarLayout(); float invIconSizeDp = isVerticalLayout ? inv.landscapeIconSize : inv.iconSize; @@ -878,7 +900,14 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("workspacePadding.right", workspacePadding.right)); writer.println(prefix + pxToDpStr("workspacePadding.bottom", workspacePadding.bottom)); + writer.println(prefix + pxToDpStr("scaleToFit", iconScale)); writer.println(prefix + pxToDpStr("extraSpace", extraSpace)); + + if (inv.devicePaddings != null) { + int unscaledExtraSpace = (int) (extraSpace / iconScale); + writer.println(prefix + pxToDpStr("maxEmptySpace", + inv.devicePaddings.getDevicePadding(unscaledExtraSpace).getMaxEmptySpacePx())); + } writer.println(prefix + pxToDpStr("workspaceTopPadding", workspaceTopPadding)); writer.println(prefix + pxToDpStr("workspaceBottomPadding", workspaceBottomPadding)); writer.println(prefix + pxToDpStr("extraHotseatBottomPadding", extraHotseatBottomPadding)); diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index b1fe4a235c..0027a50d95 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -28,6 +28,7 @@ import android.graphics.ColorFilter; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -61,6 +62,8 @@ public class FastBitmapDrawable extends Drawable { private boolean mIsPressed; private boolean mIsDisabled; private float mDisabledAlpha = 1f; + private float mRoundedCornersRadius = 0f; + private final Path mClipPath = new Path(); // Animator and properties for the fast bitmap drawable's scale private static final Property SCALE @@ -102,6 +105,13 @@ public class FastBitmapDrawable extends Drawable { @Override public final void draw(Canvas canvas) { + if (mRoundedCornersRadius > 0) { + float radius = mRoundedCornersRadius * mScale; + mClipPath.reset(); + mClipPath.addRoundRect(0, 0, getIntrinsicWidth(), getIntrinsicHeight(), + radius, radius, Path.Direction.CCW); + canvas.clipPath(mClipPath); + } if (mScale != 1f) { int count = canvas.save(); Rect bounds = getBounds(); @@ -164,6 +174,14 @@ public class FastBitmapDrawable extends Drawable { return mScale; } + public void setRoundedCornersRadius(float radius) { + mRoundedCornersRadius = radius; + } + + public float getRoundedCornersRadius() { + return mRoundedCornersRadius; + } + @Override public int getIntrinsicWidth() { return mBitmap.getWidth(); diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 348d9eef2c..b0c3bb4e81 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -132,6 +132,7 @@ public class InvariantDeviceProfile { * Do not query directly. see {@link DeviceProfile#isScalableGrid}. */ protected boolean isScalable; + public int devicePaddingId; public String dbFile; public int defaultLayoutId; @@ -140,7 +141,7 @@ public class InvariantDeviceProfile { public DeviceProfile landscapeProfile; public DeviceProfile portraitProfile; - public DevicePaddings devicePaddings; + @Nullable public DevicePaddings devicePaddings; public Point defaultWallpaperSize; public Rect defaultWidgetPadding; @@ -165,6 +166,7 @@ public class InvariantDeviceProfile { numHotseatIcons = p.numHotseatIcons; numAllAppsColumns = p.numAllAppsColumns; isScalable = p.isScalable; + devicePaddingId = p.devicePaddingId; minCellHeight = p.minCellHeight; minCellWidth = p.minCellWidth; borderSpacing = p.borderSpacing; @@ -225,13 +227,17 @@ public class InvariantDeviceProfile { .add(myDisplayOption); result.iconSize = defaultDisplayOption.iconSize; result.landscapeIconSize = defaultDisplayOption.landscapeIconSize; - result.allAppsIconSize = Math.min( - defaultDisplayOption.allAppsIconSize, myDisplayOption.allAppsIconSize); + if (defaultDisplayOption.allAppsIconSize < myDisplayOption.allAppsIconSize) { + result.allAppsIconSize = defaultDisplayOption.allAppsIconSize; + result.numAllAppsColumns = defaultDisplayOption.numAllAppsColumns; + } else { + result.allAppsIconSize = myDisplayOption.allAppsIconSize; + result.numAllAppsColumns = myDisplayOption.numAllAppsColumns; + } result.minCellHeight = defaultDisplayOption.minCellHeight; result.minCellWidth = defaultDisplayOption.minCellWidth; result.borderSpacing = defaultDisplayOption.borderSpacing; - devicePaddings = new DevicePaddings(context); initGrid(context, myInfo, result); } @@ -262,7 +268,6 @@ public class InvariantDeviceProfile { ArrayList allOptions = getPredefinedDeviceProfiles(context, gridName); DisplayOption displayOption = invDistWeightedInterpolate(displayInfo, allOptions); - devicePaddings = new DevicePaddings(context); initGrid(context, displayInfo, displayOption); return displayOption.grid.name; } @@ -278,8 +283,8 @@ public class InvariantDeviceProfile { demoModeLayoutId = closestProfile.demoModeLayoutId; numFolderRows = closestProfile.numFolderRows; numFolderColumns = closestProfile.numFolderColumns; - numAllAppsColumns = closestProfile.numAllAppsColumns; isScalable = closestProfile.isScalable; + devicePaddingId = closestProfile.devicePaddingId; mExtraAttrs = closestProfile.extraAttrs; @@ -293,6 +298,7 @@ public class InvariantDeviceProfile { minCellHeight = displayOption.minCellHeight; minCellWidth = displayOption.minCellWidth; borderSpacing = displayOption.borderSpacing; + numAllAppsColumns = Math.round(displayOption.numAllAppsColumns); if (Utilities.isGridOptionsEnabled(context)) { allAppsIconSize = displayOption.allAppsIconSize; @@ -302,6 +308,10 @@ public class InvariantDeviceProfile { allAppsIconTextSize = iconTextSize; } + if (devicePaddingId != 0) { + devicePaddings = new DevicePaddings(context, devicePaddingId); + } + // If the partner customization apk contains any grid overrides, apply them // Supported overrides: numRows, numColumns, iconSize applyPartnerDeviceProfileOverrides(context, displayInfo.metrics); @@ -609,12 +619,12 @@ public class InvariantDeviceProfile { private final int numHotseatIcons; private final String dbFile; - private final int numAllAppsColumns; private final int defaultLayoutId; private final int demoModeLayoutId; private final boolean isScalable; + private final int devicePaddingId; private final SparseArray extraAttrs; @@ -636,11 +646,11 @@ public class InvariantDeviceProfile { R.styleable.GridDisplayOption_numFolderRows, numRows); numFolderColumns = a.getInt( R.styleable.GridDisplayOption_numFolderColumns, numColumns); - numAllAppsColumns = a.getInt( - R.styleable.GridDisplayOption_numAllAppsColumns, numColumns); isScalable = a.getBoolean( R.styleable.GridDisplayOption_isScalable, false); + devicePaddingId = a.getResourceId( + R.styleable.GridDisplayOption_devicePaddingId, 0); a.recycle(); @@ -656,6 +666,7 @@ public class InvariantDeviceProfile { private final float minHeightDps; private final boolean canBeDefault; + private float numAllAppsColumns; private float minCellHeight; private float minCellWidth; private float borderSpacing; @@ -676,6 +687,8 @@ public class InvariantDeviceProfile { minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0); canBeDefault = a.getBoolean( R.styleable.ProfileDisplayOption_canBeDefault, false); + numAllAppsColumns = a.getInt(R.styleable.ProfileDisplayOption_numAllAppsColumns, + grid.numColumns); minCellHeight = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightDps, 0); minCellWidth = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthDps, 0); @@ -702,12 +715,14 @@ public class InvariantDeviceProfile { minWidthDps = 0; minHeightDps = 0; canBeDefault = false; + numAllAppsColumns = 0; minCellHeight = 0; minCellWidth = 0; borderSpacing = 0; } private DisplayOption multiply(float w) { + numAllAppsColumns *= w; iconSize *= w; landscapeIconSize *= w; allAppsIconSize *= w; @@ -720,6 +735,7 @@ public class InvariantDeviceProfile { } private DisplayOption add(DisplayOption p) { + numAllAppsColumns += p.numAllAppsColumns; iconSize += p.iconSize; landscapeIconSize += p.landscapeIconSize; allAppsIconSize += p.allAppsIconSize; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 89c0f6697e..8785fbc2b9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2763,6 +2763,13 @@ public class Launcher extends StatefulActivity implements Launche return new float[] {NO_SCALE, NO_OFFSET}; } + /** + * @see LauncherState#getTaskbarScale(Launcher) + */ + public float getNormalTaskbarScale() { + return 1f; + } + public static Launcher getLauncher(Context context) { return fromContext(context); } diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index 06bc4380fa..46bce937bf 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -176,6 +176,10 @@ public abstract class LauncherState implements BaseState { return launcher.getNormalOverviewScaleAndOffset(); } + public float getTaskbarScale(Launcher launcher) { + return launcher.getNormalTaskbarScale(); + } + public float getOverviewFullscreenProgress() { return 0; } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 65fde8659a..76885ccbc8 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1512,17 +1512,16 @@ public abstract class PagedView extends ViewGrou return getDestinationPage(mOrientationHandler.getPrimaryScroll(this)); } - protected int getDestinationPage(int scaledScroll) { - return getPageNearestToCenterOfScreen(scaledScroll); + protected int getDestinationPage(int primaryScroll) { + return getPageNearestToCenterOfScreen(primaryScroll); } public int getPageNearestToCenterOfScreen() { return getPageNearestToCenterOfScreen(mOrientationHandler.getPrimaryScroll(this)); } - private int getPageNearestToCenterOfScreen(int scaledScroll) { - int pageOrientationSize = mOrientationHandler.getMeasuredSize(this); - int screenCenter = scaledScroll + (pageOrientationSize / 2); + private int getPageNearestToCenterOfScreen(int primaryScroll) { + int screenCenter = getScreenCenter(primaryScroll); int minDistanceFromScreenCenter = Integer.MAX_VALUE; int minDistanceFromScreenCenterIndex = -1; final int childCount = getChildCount(); @@ -1538,18 +1537,26 @@ public abstract class PagedView extends ViewGrou } private int getDisplacementFromScreenCenter(int childIndex, int screenCenter) { - int childSize = getChildVisibleSize(childIndex); + int childSize = Math.round(getChildVisibleSize(childIndex)); int halfChildSize = (childSize / 2); int childCenter = getChildOffset(childIndex) + halfChildSize; return childCenter - screenCenter; } protected int getDisplacementFromScreenCenter(int childIndex) { - int pageOrientationSize = mOrientationHandler.getMeasuredSize(this); - int screenCenter = mOrientationHandler.getPrimaryScroll(this) + (pageOrientationSize / 2); + int primaryScroll = mOrientationHandler.getPrimaryScroll(this); + int screenCenter = getScreenCenter(primaryScroll); return getDisplacementFromScreenCenter(childIndex, screenCenter); } + private int getScreenCenter(int primaryScroll) { + float primaryScale = mOrientationHandler.getPrimaryScale(this); + float primaryPivot = mOrientationHandler.getPrimaryValue(getPivotX(), getPivotY()); + int pageOrientationSize = mOrientationHandler.getMeasuredSize(this); + return Math.round(primaryScroll + (pageOrientationSize / 2f - primaryPivot) / primaryScale + + primaryPivot); + } + protected void snapToDestination() { snapToPage(getDestinationPage(), getPageSnapDuration()); } diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 6db7a752d1..16e022ca85 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -34,7 +34,6 @@ import static com.android.launcher3.anim.Interpolators.ZOOM_OUT; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS; import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; @@ -133,8 +132,7 @@ public class WorkspaceStateTransitionAnimation { } float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0; - propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, - config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator)); + propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator); float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0; propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(), workspacePageIndicatorAlpha, fadeInterpolator); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 591de043d2..bf0a88f33f 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -583,10 +583,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo int padding = mHeader.getMaxTranslation(); for (int i = 0; i < mAH.length; i++) { mAH[i].padding.top = padding; - if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mUsingTabs) { - //add extra space between tabs and recycler view - mAH[i].padding.top += mLauncher.getDeviceProfile().edgeMarginPx; - } mAH[i].applyPadding(); } } diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java index 14e3b5140f..3cc9ce6806 100644 --- a/src/com/android/launcher3/allapps/AllAppsPagedView.java +++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java @@ -23,8 +23,6 @@ import android.util.AttributeSet; import com.android.launcher3.Launcher; import com.android.launcher3.PagedView; -import com.android.launcher3.R; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.workprofile.PersonalWorkPagedView; /** @@ -43,10 +41,6 @@ public class AllAppsPagedView extends PersonalWorkPagedView { public AllAppsPagedView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - int topPadding = FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0 - : context.getResources().getDimensionPixelOffset( - R.dimen.all_apps_header_top_padding); - setPadding(0, topPadding, 0, 0); } @Override diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java index 86f330c88d..733d867e4d 100644 --- a/src/com/android/launcher3/allapps/FloatingHeaderView.java +++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java @@ -106,8 +106,8 @@ public class FloatingHeaderView extends LinearLayout implements public FloatingHeaderView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); - mHeaderTopPadding = FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0 : - context.getResources().getDimensionPixelSize(R.dimen.all_apps_header_top_padding); + mHeaderTopPadding = context.getResources() + .getDimensionPixelSize(R.dimen.all_apps_header_top_padding); } @Override @@ -125,7 +125,6 @@ public class FloatingHeaderView extends LinearLayout implements } } mFixedRows = rows.toArray(new FloatingHeaderRow[rows.size()]); - setPadding(0, mHeaderTopPadding, 0, 0); mAllRows = mFixedRows; } @@ -243,9 +242,7 @@ public class FloatingHeaderView extends LinearLayout implements public int getMaxTranslation() { if (mMaxTranslation == 0 && mTabsHidden) { - int paddingOffset = getResources().getDimensionPixelSize( - R.dimen.all_apps_search_bar_bottom_padding); - return FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0 : paddingOffset; + return getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_bottom_padding); } else if (mMaxTranslation > 0 && mTabsHidden) { return mMaxTranslation + getPaddingTop(); } else { diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java index 6b9ed09c77..7980138370 100644 --- a/src/com/android/launcher3/anim/Interpolators.java +++ b/src/com/android/launcher3/anim/Interpolators.java @@ -77,6 +77,9 @@ public class Interpolators { public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = new PathInterpolator(0.3f, 0f, 0.1f, 1f); + public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL = + v -> ACCEL_DEACCEL.getInterpolation(TOUCH_RESPONSE_INTERPOLATOR.getInterpolation(v)); + /** * Inversion of ZOOM_OUT, compounded with an ease-out. diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java index e4c67eee7c..cd74390418 100644 --- a/src/com/android/launcher3/states/StateAnimationConfig.java +++ b/src/com/android/launcher3/states/StateAnimationConfig.java @@ -38,7 +38,6 @@ public class StateAnimationConfig { PLAY_ATOMIC_OVERVIEW_PEEK, SKIP_OVERVIEW, SKIP_DEPTH_CONTROLLER, - SKIP_TASKBAR, }) @Retention(RetentionPolicy.SOURCE) public @interface AnimationFlags {} @@ -47,7 +46,6 @@ public class StateAnimationConfig { public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2; public static final int SKIP_OVERVIEW = 1 << 3; public static final int SKIP_DEPTH_CONTROLLER = 1 << 4; - public static final int SKIP_TASKBAR = 1 << 5; public long duration; public boolean userControlled; @@ -74,8 +72,6 @@ public class StateAnimationConfig { ANIM_OVERVIEW_MODAL, ANIM_DEPTH, ANIM_OVERVIEW_ACTIONS_FADE, - ANIM_TASKBAR_FADE, - ANIM_HOTSEAT_FADE, }) @Retention(RetentionPolicy.SOURCE) public @interface AnimType {} @@ -95,10 +91,8 @@ public class StateAnimationConfig { public static final int ANIM_OVERVIEW_MODAL = 13; public static final int ANIM_DEPTH = 14; public static final int ANIM_OVERVIEW_ACTIONS_FADE = 15; - public static final int ANIM_TASKBAR_FADE = 16; - public static final int ANIM_HOTSEAT_FADE = 17; // if not set, falls back to ANIM_WORKSPACE_FADE - private static final int ANIM_TYPES_COUNT = 18; + private static final int ANIM_TYPES_COUNT = 16; protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT]; diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index c1cf0c8ec2..19dfe15f62 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -136,7 +136,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { } @Override - public int getClearAllScrollOffset(View view, boolean isRtl) { + public int getClearAllSidePadding(View view, boolean isRtl) { return (isRtl ? view.getPaddingBottom() : - view.getPaddingTop()) / 2; } diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index fcfa205ed2..9140a04341 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -66,7 +66,7 @@ public interface PagedOrientationHandler { float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId); int getMeasuredSize(View view); float getPrimarySize(RectF rect); - int getClearAllScrollOffset(View view, boolean isRtl); + int getClearAllSidePadding(View view, boolean isRtl); int getSecondaryDimension(View view); FloatProperty getPrimaryViewTranslate(); FloatProperty getSecondaryViewTranslate(); diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 2bc2dc7d93..29be62733c 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -132,7 +132,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } @Override - public int getClearAllScrollOffset(View view, boolean isRtl) { + public int getClearAllSidePadding(View view, boolean isRtl) { return (isRtl ? view.getPaddingRight() : - view.getPaddingLeft()) / 2; } diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java index 0ea0290a8b..5be95292b4 100644 --- a/src/com/android/launcher3/util/MultiValueAlpha.java +++ b/src/com/android/launcher3/util/MultiValueAlpha.java @@ -42,43 +42,16 @@ public class MultiValueAlpha { } }; - /** - * Determines how each alpha should factor into the final alpha. - */ - public enum Mode { - BLEND() { - @Override - public float calculateNewAlpha(float currentAlpha, float otherAlpha) { - return currentAlpha * otherAlpha; - } - }, - - MAX() { - @Override - public float calculateNewAlpha(float currentAlpha, float otherAlpha) { - return Math.max(currentAlpha, otherAlpha); - } - }; - - protected abstract float calculateNewAlpha(float currentAlpha, float otherAlpha); - } - private final View mView; private final AlphaProperty[] mMyProperties; - private final Mode mMode; private int mValidMask; // Whether we should change from INVISIBLE to VISIBLE and vice versa at low alpha values. private boolean mUpdateVisibility; public MultiValueAlpha(View view, int size) { - this(view, size, Mode.BLEND); - } - - public MultiValueAlpha(View view, int size, Mode mode) { mView = view; mMyProperties = new AlphaProperty[size]; - mMode = mode; mValidMask = 0; for (int i = 0; i < size; i++) { @@ -124,7 +97,7 @@ public class MultiValueAlpha { mOthers = 1; for (AlphaProperty prop : mMyProperties) { if (prop != this) { - mOthers = mMode.calculateNewAlpha(mOthers, prop.mValue); + mOthers *= prop.mValue; } } } @@ -134,7 +107,7 @@ public class MultiValueAlpha { mValidMask = mMyMask; mValue = value; - mView.setAlpha(mMode.calculateNewAlpha(mOthers, mValue)); + mView.setAlpha(mOthers * mValue); if (mUpdateVisibility) { AlphaUpdateListener.updateVisibility(mView); } diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 2e542edf76..687318f775 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -497,12 +497,13 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView @UiThread private void enforceRoundedCorners() { - if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled(this)) { + if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) { resetRoundedCorners(); return; } View background = RoundedCornerEnforcement.findBackground(this); - if (RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) { + if (background == null + || RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) { resetRoundedCorners(); return; } diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java index 8689fbfd3c..ad61495de8 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java @@ -139,6 +139,10 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo } } + public boolean isReconfigurable() { + return configure != null && (getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) != 0; + } + @Override public final ComponentName getComponent() { return provider; diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java index 247a748ba6..08bb66211c 100644 --- a/src/com/android/launcher3/widget/PendingItemDragHelper.java +++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java @@ -54,10 +54,13 @@ public class PendingItemDragHelper extends DragPreviewProvider { @Nullable private RemoteViews mRemoteViewsPreview; @Nullable private LauncherAppWidgetHostView mAppWidgetHostViewPreview; + private final float mEnforcedRoundedCornersForWidget; public PendingItemDragHelper(View view) { super(view); mAddInfo = (PendingAddItemInfo) view.getTag(); + mEnforcedRoundedCornersForWidget = RoundedCornerEnforcement.computeEnforcedRadius( + view.getContext()); } /** @@ -115,10 +118,14 @@ public class PendingItemDragHelper extends DragPreviewProvider { .addDragListener(new AppWidgetHostViewDragListener(launcher)); } if (preview == null) { - preview = new FastBitmapDrawable( + FastBitmapDrawable p = new FastBitmapDrawable( app.getWidgetCache().generateWidgetPreview(launcher, createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale).first); + if (RoundedCornerEnforcement.isRoundedCornerEnabled()) { + p.setRoundedCornersRadius(mEnforcedRoundedCornersForWidget); + } + preview = p; } if (previewSizeBeforeScale[0] < previewBitmapWidth) { diff --git a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java index 99eccd1303..1e46ffd30c 100644 --- a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java +++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java @@ -72,12 +72,8 @@ public class RoundedCornerEnforcement { } /** Check if the app widget is in the deny list. */ - public static boolean isRoundedCornerEnabled(@NonNull View view) { - if (!Utilities.ATLEAST_S || !FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get()) { - return false; - } - // Here we need to test if the view's component is in the (to be created) deny list. - return true; + public static boolean isRoundedCornerEnabled() { + return Utilities.ATLEAST_S && FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get(); } /** diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index 1b0e1ce0b2..2b4b9ea55e 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -94,6 +94,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { protected final BaseActivity mActivity; protected final DeviceProfile mDeviceProfile; private final CheckLongPressHelper mLongPressHelper; + private final float mEnforcedCornerRadius; private RemoteViews mPreview; private LauncherAppWidgetHostView mAppWidgetHostViewPreview; @@ -118,6 +119,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { setWillNotDraw(false); setClipToPadding(false); setAccessibilityDelegate(mActivity.getAccessibilityDelegate()); + mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context); } private void setContainerWidth() { @@ -245,7 +247,9 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { } public void applyPreview(Bitmap bitmap) { - applyPreview(new FastBitmapDrawable(bitmap)); + FastBitmapDrawable drawable = new FastBitmapDrawable(bitmap); + drawable.setRoundedCornersRadius(mEnforcedCornerRadius); + applyPreview(drawable); } private void applyPreview(Drawable drawable) { diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 2fda86c89c..bbb0d92eac 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -26,6 +26,7 @@ import android.util.IntProperty; import android.util.Pair; import android.view.Gravity; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.Interpolator; @@ -152,6 +153,19 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { }); } + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mNoIntercept = false; + ScrollView scrollView = findViewById(R.id.widgets_table_scroll_view); + if (getPopupContainer().isEventOverView(scrollView, ev) + && scrollView.getScrollY() > 0) { + mNoIntercept = true; + } + } + return super.onControllerInterceptTouchEvent(ev); + } + protected WidgetCell addItemCell(ViewGroup parent) { WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext()) .inflate(R.layout.widget_cell, parent, false); diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index dc7d341546..29c00b209f 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -58,6 +58,7 @@ import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListene import com.android.launcher3.widget.model.WidgetsListBaseEntry; import com.android.launcher3.widget.picker.search.SearchModeListener; import com.android.launcher3.widget.picker.search.WidgetsSearchBar; +import com.android.launcher3.widget.picker.search.WidgetsSearchBarUIHelper; import com.android.launcher3.widget.util.WidgetsTableUtils; import com.android.launcher3.workprofile.PersonalWorkPagedView; import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener; @@ -71,7 +72,8 @@ import java.util.function.Predicate; */ public class WidgetsFullSheet extends BaseWidgetSheet implements Insettable, ProviderChangedListener, OnActivePageChangedListener, - WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener { + WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener, + WidgetsSearchBarUIHelper { private static final String TAG = WidgetsFullSheet.class.getSimpleName(); private static final long DEFAULT_OPEN_DURATION = 267; @@ -561,6 +563,11 @@ public class WidgetsFullSheet extends BaseWidgetSheet getWindowInsetsController().hide(WindowInsets.Type.ime()); } + @Override + public void clearSearchBarFocus() { + mSearchAndRecommendationViewHolder.mSearchBar.clearSearchBarFocus(); + } + /** A holder class for holding adapters & their corresponding recycler view. */ private final class AdapterHolder { static final int PRIMARY = 0; @@ -583,7 +590,9 @@ public class WidgetsFullSheet extends BaseWidgetSheet apps.getWidgetCache(), apps.getIconCache(), /* iconClickListener= */ WidgetsFullSheet.this, - /* iconLongClickListener= */ WidgetsFullSheet.this); + /* iconLongClickListener= */ WidgetsFullSheet.this, + /* WidgetsSearchBarUIHelper= */ + mAdapterType == SEARCH ? WidgetsFullSheet.this : null); mWidgetsListAdapter.setHasStableIds(true); switch (mAdapterType) { case PRIMARY: diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java index d841c64a3c..d9c9d4d71b 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java @@ -41,6 +41,7 @@ import com.android.launcher3.widget.model.WidgetsListBaseEntry; import com.android.launcher3.widget.model.WidgetsListContentEntry; import com.android.launcher3.widget.model.WidgetsListHeaderEntry; import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry; +import com.android.launcher3.widget.picker.search.WidgetsSearchBarUIHelper; import java.util.ArrayList; import java.util.Arrays; @@ -69,6 +70,7 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC private static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header; private static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header; + @Nullable private final WidgetsSearchBarUIHelper mSearchBarUIHelper; private final WidgetsDiffReporter mDiffReporter; private final SparseArray mViewHolderBinders = new SparseArray<>(); private final WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder; @@ -88,7 +90,9 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC public WidgetsListAdapter(Context context, LayoutInflater layoutInflater, WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache, - OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) { + OnClickListener iconClickListener, OnLongClickListener iconLongClickListener, + @Nullable WidgetsSearchBarUIHelper searchBarUIHelper) { + mSearchBarUIHelper = searchBarUIHelper; mDiffReporter = new WidgetsDiffReporter(iconCache, this); mWidgetsListTableViewHolderBinder = new WidgetsListTableViewHolderBinder(context, layoutInflater, iconClickListener, iconLongClickListener, @@ -237,6 +241,9 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC @Override public void onHeaderClicked(boolean showWidgets, PackageUserKey packageUserKey) { + if (mSearchBarUIHelper != null) { + mSearchBarUIHelper.clearSearchBarFocus(); + } if (showWidgets) { mWidgetsContentVisiblePackageUserKey = packageUserKey; updateVisibleEntries(); diff --git a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java index cc336196ae..56a08b16fb 100644 --- a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java +++ b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java @@ -79,4 +79,9 @@ public class LauncherWidgetsSearchBar extends LinearLayout implements WidgetsSea super.onDetachedFromWindow(); mController.onDestroy(); } + + @Override + public void clearSearchBarFocus() { + mController.clearFocus(); + } } diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java index ef7bf23226..3ac82c0ca7 100644 --- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java +++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java @@ -34,6 +34,11 @@ public interface WidgetsSearchBar { */ void reset(); + /** + * Clears focus from search bar. + */ + void clearSearchBarFocus(); + /** * Sets the vertical location, in pixels, of this search bar relative to its top position. */ diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java index 60110977ed..d35a75b80a 100644 --- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java +++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java @@ -103,8 +103,7 @@ public class WidgetsSearchBarController implements TextWatcher, public void clearSearchResult() { mSearchAlgorithm.cancel(/* interruptActiveRequests= */ true); mInput.getText().clear(); - mInput.clearFocus(); - mInput.hideKeyboard(); + clearFocus(); mSearchModeListener.exitSearchMode(); } @@ -117,18 +116,24 @@ public class WidgetsSearchBarController implements TextWatcher, @Override public boolean onBackKey() { - mInput.clearFocus(); - mInput.hideKeyboard(); + clearFocus(); return true; } @Override public boolean onKey(View view, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { - mInput.clearFocus(); - mInput.hideKeyboard(); + clearFocus(); return true; } return false; } + + /** + * Clears focus from edit text. + */ + public void clearFocus() { + mInput.clearFocus(); + mInput.hideKeyboard(); + } } diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarUIHelper.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarUIHelper.java new file mode 100644 index 0000000000..edfdc655ed --- /dev/null +++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarUIHelper.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 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. + */ + +package com.android.launcher3.widget.picker.search; + +/** + * UI helper for {@link WidgetsSearchBar}. + */ +public interface WidgetsSearchBarUIHelper { + /** + * Clears focus from the search bar. + */ + void clearSearchBarFocus(); +}