Merge "Update app widget resize frame UI." into sc-dev
diff --git a/Android.bp b/Android.bp
index cca48ce..002f6fe 100644
--- a/Android.bp
+++ b/Android.bp
@@ -93,3 +93,93 @@
sdk_version: "current",
min_sdk_version: "28",
}
+
+//
+// Build rule for Launcher3 dependencies lib.
+//
+android_library {
+ name: "Launcher3CommonDepsLib",
+ static_libs: [
+ "androidx.recyclerview_recyclerview",
+ "androidx.dynamicanimation_dynamicanimation",
+ "androidx.preference_preference",
+ "androidx.slice_slice-view",
+ "iconloader_base",
+ "LauncherPluginLib",
+ "launcher_quickstep_log_protos_lite"
+ ],
+ srcs: [
+ "src_build_config/**/*.java",
+ ],
+ resource_dirs: ["res"],
+ optimize: {
+ enabled: false,
+ },
+ sdk_version: "current",
+ min_sdk_version: "26",
+ manifest: "AndroidManifest-common.xml",
+}
+
+//
+// Build rule for Launcher3 app.
+//
+android_app {
+ name: "Launcher3",
+
+ static_libs: [
+ "Launcher3CommonDepsLib",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "src_shortcuts_overrides/**/*.java",
+ "src_ui_overrides/**/*.java",
+ "ext_tests/src/**/*.java",
+ ],
+ resource_dirs: [
+ "ext_tests/res",
+ ],
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ // Proguard is disable for testing. Derivarive prjects to keep proguard enabled
+ enabled: false,
+ },
+
+ sdk_version: "current",
+ min_sdk_version: "26",
+ target_sdk_version: "29",
+ privileged: true,
+ system_ext_specific: true,
+
+ overrides: [
+ "Home",
+ "Launcher2",
+ ],
+ required: ["privapp_whitelist_com.android.launcher3"],
+
+ jacoco: {
+ include_filter: ["com.android.launcher3.**"],
+ },
+ additional_manifests: [
+ "AndroidManifest-common.xml",
+ ],
+}
+
+//
+// Launcher Robolectric test target.
+//
+java_library {
+ name: "Launcher3TestCommon",
+ libs: [
+ "Launcher3CommonDepsLib",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "src_shortcuts_overrides/**/*.java",
+ "src_ui_overrides/**/*.java",
+ "ext_tests/src/**/*.java",
+ "tests/src_common/**/*.java",
+ ],
+ target_sdk_version: "29",
+ sdk_version: "current",
+ min_sdk_version: "26",
+}
diff --git a/Android.mk b/Android.mk
index 304935b..89870a6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,79 +17,6 @@
LOCAL_PATH := $(call my-dir)
#
-# Build rule for Launcher3 dependencies lib.
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- androidx.recyclerview_recyclerview \
- androidx.dynamicanimation_dynamicanimation \
- androidx.preference_preference \
- androidx.slice_slice-view \
- iconloader_base
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- LauncherPluginLib \
- launcher_quickstep_log_protos_lite \
- search_ui
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src_build_config) \
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 26
-LOCAL_MODULE := Launcher3CommonDepsLib
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_MANIFEST_FILE := AndroidManifest-common.xml
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-#
-# Build rule for Launcher3 app.
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-java-files-under, src_shortcuts_overrides) \
- $(call all-java-files-under, src_ui_overrides) \
- $(call all-java-files-under, ext_tests/src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/ext_tests/res
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-# Proguard is disable for testing. Derivarive prjects to keep proguard enabled
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 26
-LOCAL_PACKAGE_NAME := Launcher3
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_SYSTEM_EXT_MODULE := true
-LOCAL_OVERRIDES_PACKAGES := Home Launcher2
-LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
-
-LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest-common.xml
-
-LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
-
-include $(BUILD_PACKAGE)
-
-#
# Build rule for Launcher3 Go app for Android Go devices.
#
include $(CLEAR_VARS)
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 5b30143..161c98e 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -35,6 +35,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.proxy.ProxyActivityStarter;
@@ -83,6 +84,8 @@
private @Nullable TaskbarController mTaskbarController;
private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
+ // Will be updated when dragging from taskbar.
+ private DragOptions mWorkspaceDragOptions = new DragOptions();
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -270,6 +273,15 @@
}
@Override
+ public DragOptions getDefaultWorkspaceDragOptions() {
+ return mWorkspaceDragOptions;
+ }
+
+ public void setWorkspaceDragOptions(DragOptions dragOptions) {
+ mWorkspaceDragOptions = dragOptions;
+ }
+
+ @Override
public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
QuickstepAppTransitionManagerImpl appTransitionManager =
(QuickstepAppTransitionManagerImpl) getAppTransitionManager();
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index b570d55..83234e3 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -41,7 +41,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsSectionDecorator;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.AlphaUpdateListener;
@@ -106,8 +105,6 @@
private boolean mPredictionsEnabled = false;
- AllAppsSectionDecorator.SectionDecorationHandler mDecorationHandler;
-
@Nullable
private List<ItemInfo> mPendingPredictedItems;
@@ -129,11 +126,6 @@
mIconFullTextAlpha = Color.alpha(mIconTextColor);
mIconCurrentTextAlpha = mIconFullTextAlpha;
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- mDecorationHandler = new AllAppsSectionDecorator.SectionDecorationHandler(getContext(),
- false, 0, true, true);
- }
-
updateVisibility();
}
@@ -159,16 +151,6 @@
@Override
protected void dispatchDraw(Canvas canvas) {
- if (mDecorationHandler != null) {
- mDecorationHandler.reset();
- int childrenCount = getChildCount();
- for (int i = 0; i < childrenCount; i++) {
- mDecorationHandler.extendBounds(getChildAt(i));
- }
- mDecorationHandler.onGroupDraw(canvas);
- mDecorationHandler.onFocusDraw(canvas, getFocusedChild());
- mLauncher.getAppsView().getActiveRecyclerView().invalidateItemDecorations();
- }
mFocusHelper.draw(canvas);
super.dispatchDraw(canvas);
}
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 0156e8f..f297343 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -107,7 +107,8 @@
WorkspaceItemInfo dragItem = new WorkspaceItemInfo((WorkspaceItemInfo) v.getTag());
v.setVisibility(View.INVISIBLE);
mLauncher.getWorkspace().beginDragShared(
- v, null, this, dragItem, new DragPreviewProvider(v), new DragOptions());
+ v, null, this, dragItem, new DragPreviewProvider(v),
+ mLauncher.getDefaultWorkspaceDragOptions());
return true;
};
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 06372fe..8312b82 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -35,13 +35,14 @@
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);
- float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
- mDeviceProfile.updateIconSize(iconScale, getResources());
+ mIconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
+ mDeviceProfile.updateIconSize(mIconScale, getResources());
mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
@@ -75,4 +76,11 @@
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/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
index ddd0d15..1e5e3e7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
@@ -97,7 +97,12 @@
// to show a floating view like Folder. Thus, we set the contentInsets to be where
// mTaskbarView is, since its position never changes and insets rather than overlays.
int[] loc = mTempLoc;
+ float scale = mTaskbarView.getScaleX();
+ mTaskbarView.setScaleX(1);
+ mTaskbarView.setScaleY(1);
mTaskbarView.getLocationInWindow(loc);
+ mTaskbarView.setScaleX(scale);
+ mTaskbarView.setScaleY(scale);
insetsInfo.contentInsets.left = loc[0];
insetsInfo.contentInsets.top = loc[1];
insetsInfo.contentInsets.right = getWidth() - (loc[0] + mTaskbarView.getWidth());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index 5dddaf3..74a82ab 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -19,14 +19,18 @@
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;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.ActivityOptions;
import android.content.ComponentName;
import android.graphics.PixelFormat;
import android.graphics.Point;
+import android.graphics.Rect;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -81,6 +85,8 @@
// Contains all loaded Hotseat items.
private ItemInfo[] mLatestLoadedHotseatItems;
+ private boolean mIsAnimatingToLauncher;
+
public TaskbarController(BaseQuickstepLauncher launcher,
TaskbarContainerView taskbarContainerView) {
mLauncher = launcher;
@@ -164,7 +170,22 @@
@Override
public View.OnLongClickListener getItemOnLongClickListener() {
- return mDragController::startDragOnLongClick;
+ return view -> {
+ if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) {
+ alignRealHotseatWithTaskbar();
+ return mDragController.startWorkspaceDragOnLongClick(view);
+ } else {
+ return mDragController.startSystemDragOnLongClick(view);
+ }
+ };
+ }
+
+ @Override
+ public int getEmptyHotseatViewVisibility() {
+ // When on the home screen, we want the empty hotseat views to take up their full
+ // space so that the others line up with the home screen hotseat.
+ return mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
+ ? View.INVISIBLE : View.GONE;
}
};
}
@@ -207,6 +228,8 @@
mTaskbarVisibilityController.init();
mHotseatController.init();
mRecentsController.init();
+
+ SCALE_PROPERTY.set(mTaskbarView, mLauncher.hasBeenResumed() ? getTaskbarScaleOnHome() : 1f);
}
private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() {
@@ -290,11 +313,38 @@
if (toState != null) {
mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
}
+ anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(),
+ getTaskbarScaleOnHome(), LINEAR);
+
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncher = true;
+ mTaskbarView.updateHotseatItemsVisibility();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncher = false;
+ }
+ });
+
+ anim.addOnFrameCallback(this::alignRealHotseatWithTaskbar);
+
return anim.buildAnim();
}
private Animator createAnimToApp(long duration) {
- return mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration);
+ PendingAnimation anim = new PendingAnimation(duration);
+ anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration));
+ anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), 1f, LINEAR);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTaskbarView.updateHotseatItemsVisibility();
+ }
+ });
+ return anim.buildAnim();
}
/**
@@ -378,6 +428,21 @@
}
/**
+ * Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat.
+ */
+ public void alignRealHotseatWithTaskbar() {
+ Rect hotseatBounds = new Rect();
+ mTaskbarView.getHotseatBoundsAtScale(getTaskbarScaleOnHome()).roundOut(hotseatBounds);
+ mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top,
+ mTaskbarView.getWidth() - hotseatBounds.right,
+ mTaskbarView.getHeight() - hotseatBounds.bottom);
+ }
+
+ private float getTaskbarScaleOnHome() {
+ return 1f / mTaskbarContainerView.getTaskbarActivityContext().getTaskbarIconScale();
+ }
+
+ /**
* Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
*/
private void setTaskbarWindowFullscreen(boolean fullscreen) {
@@ -420,6 +485,7 @@
protected interface TaskbarViewCallbacks {
View.OnClickListener getItemOnClickListener();
View.OnLongClickListener getItemOnLongClickListener();
+ int getEmptyHotseatViewVisibility();
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index baec899..f51e498 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -33,6 +33,7 @@
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;
@@ -57,7 +58,7 @@
* generate the ClipDescription and Intent.
* @return Whether {@link View#startDragAndDrop} started successfully.
*/
- protected boolean startDragOnLongClick(View view) {
+ protected boolean startSystemDragOnLongClick(View view) {
if (!(view instanceof BubbleTextView)) {
return false;
}
@@ -125,6 +126,38 @@
}
/**
+ * 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.
*/
private View.OnDragListener getDraggedViewDragListener() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java
new file mode 100644
index 0000000..2bd5861
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+ private final DragOptions mDragOptions;
+ // 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;
+ mDragOptions = new DragOptions();
+ mDragOptions.simulatedDndStartPoint = new Point();
+ mId = UUID.randomUUID().toString();
+ }
+
+ protected void init(DragLayer dragLayer) {
+ mDragLayer = dragLayer;
+ mDragLayer.setOnDragListener(this);
+ }
+
+ private void cleanup() {
+ mDragLayer.setOnDragListener(null);
+ mLauncher.setWorkspaceDragOptions(new DragOptions());
+ }
+
+ /**
+ * 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;
+ }
+ mDragOptions.simulatedDndStartPoint.set((int) dragEvent.getX(), (int) dragEvent.getY());
+ mLauncher.setWorkspaceDragOptions(mDragOptions);
+ 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/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 7a13b89..a729e77 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -35,6 +36,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -50,10 +52,12 @@
private final ColorDrawable mBackgroundDrawable;
private final int mItemMarginLeftRight;
private final int mIconTouchSize;
+ private final boolean mIsRtl;
private final int mTouchSlop;
private final RectF mTempDelegateBounds = new RectF();
private final RectF mDelegateSlopBounds = new RectF();
private final int[] mTempOutLocation = new int[2];
+ private final Matrix mTempMatrix = new Matrix();
// Initialized in TaskbarController constructor.
private TaskbarController.TaskbarViewCallbacks mControllerCallbacks;
@@ -94,6 +98,7 @@
mBackgroundDrawable = (ColorDrawable) getBackground();
mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
+ mIsRtl = Utilities.isRtl(resources);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
@@ -131,7 +136,8 @@
*/
protected void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
for (int i = 0; i < hotseatItemInfos.length; i++) {
- ItemInfo hotseatItemInfo = hotseatItemInfos[i];
+ ItemInfo hotseatItemInfo = hotseatItemInfos[!mIsRtl ? i
+ : hotseatItemInfos.length - i - 1];
int hotseatIndex = mHotseatStartIndex + i;
View hotseatView = getChildAt(hotseatIndex);
@@ -176,25 +182,45 @@
&& hotseatItemInfo instanceof WorkspaceItemInfo) {
((BubbleTextView) hotseatView).applyFromWorkspaceItem(
(WorkspaceItemInfo) hotseatItemInfo);
- hotseatView.setVisibility(VISIBLE);
hotseatView.setOnClickListener(mControllerCallbacks.getItemOnClickListener());
hotseatView.setOnLongClickListener(
mControllerCallbacks.getItemOnLongClickListener());
} else if (isFolder) {
- hotseatView.setVisibility(VISIBLE);
hotseatView.setOnClickListener(mControllerCallbacks.getItemOnClickListener());
hotseatView.setOnLongClickListener(
mControllerCallbacks.getItemOnLongClickListener());
} else {
- hotseatView.setVisibility(GONE);
hotseatView.setOnClickListener(null);
hotseatView.setOnLongClickListener(null);
+ hotseatView.setTag(null);
}
+ updateHotseatItemVisibility(hotseatView);
}
updateHotseatRecentsDividerVisibility();
}
+ protected void updateHotseatItemsVisibility() {
+ for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) {
+ updateHotseatItemVisibility(getChildAt(i));
+ }
+ }
+
+ private void updateHotseatItemVisibility(View hotseatView) {
+ if (hotseatView.getTag() != null) {
+ hotseatView.setVisibility(VISIBLE);
+ } else {
+ int oldVisibility = hotseatView.getVisibility();
+ int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility();
+ hotseatView.setVisibility(newVisibility);
+ if (oldVisibility == GONE && newVisibility != GONE) {
+ // By default, the layout transition only runs when going to VISIBLE,
+ // but we want it to run when going to GONE to INVISIBLE as well.
+ getLayoutTransition().showChild(this, hotseatView, oldVisibility);
+ }
+ }
+ }
+
private View addDivider(int dividerIndex) {
View divider = inflate(R.layout.taskbar_divider);
addView(divider, dividerIndex);
@@ -390,6 +416,35 @@
return mIsDraggingItem;
}
+ /**
+ * @return The bounding box of where the hotseat elements will be when we reach the given scale.
+ */
+ protected RectF getHotseatBoundsAtScale(float taskbarViewScale) {
+ View firstHotseatView = null, lastHotseatView = null;
+ for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ if (firstHotseatView == null) {
+ firstHotseatView = child;
+ }
+ lastHotseatView = child;
+ }
+ }
+ if (firstHotseatView == null || lastHotseatView == null) {
+ return new RectF();
+ }
+ View leftmostHotseatView = !mIsRtl ? firstHotseatView : lastHotseatView;
+ View rightmostHotseatView = !mIsRtl ? lastHotseatView : firstHotseatView;
+ RectF hotseatBounds = new RectF(
+ leftmostHotseatView.getLeft() - mItemMarginLeftRight,
+ leftmostHotseatView.getTop(),
+ rightmostHotseatView.getRight() + mItemMarginLeftRight,
+ rightmostHotseatView.getBottom());
+ mTempMatrix.setScale(taskbarViewScale, taskbarViewScale, getPivotX(), getPivotY());
+ mTempMatrix.mapRect(hotseatBounds);
+ return hotseatBounds;
+ }
+
// FolderIconParent implemented methods.
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 98551fb..d330a68 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -228,17 +228,13 @@
*/
public static class PredictedIconOutlineDrawing extends CellLayout.DelegatedCellDrawing {
- private int mOffsetX;
- private int mOffsetY;
- private int mIconRadius;
- private Paint mOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final PredictedAppIcon mIcon;
+ private final Paint mOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public PredictedIconOutlineDrawing(int cellX, int cellY, PredictedAppIcon icon) {
mDelegateCellX = cellX;
mDelegateCellY = cellY;
- mOffsetX = icon.getOutlineOffsetX();
- mOffsetY = icon.getOutlineOffsetY();
- mIconRadius = icon.mNormalizedIconRadius;
+ mIcon = icon;
mOutlinePaint.setStyle(Paint.Style.FILL);
mOutlinePaint.setColor(Color.argb(24, 245, 245, 245));
}
@@ -248,7 +244,8 @@
*/
@Override
public void drawUnderItem(Canvas canvas) {
- getShape().drawShape(canvas, mOffsetX, mOffsetY, mIconRadius, mOutlinePaint);
+ getShape().drawShape(canvas, mIcon.getOutlineOffsetX(), mIcon.getOutlineOffsetY(),
+ mIcon.mNormalizedIconRadius, mOutlinePaint);
}
/**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 69b8aca..473fe2d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -18,6 +18,7 @@
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;
@@ -32,6 +33,7 @@
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;
@@ -48,7 +50,6 @@
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.AllAppsContainerView;
@@ -62,7 +63,7 @@
* Animation factory for quickstep specific transitions
*/
public class QuickstepAtomicAnimationFactory extends
- RecentsAtomicAnimationFactory<Launcher, LauncherState> {
+ RecentsAtomicAnimationFactory<QuickstepLauncher, LauncherState> {
// Scale recents takes before animating in
private static final float RECENTS_PREPARE_SCALE = 1.33f;
@@ -149,6 +150,17 @@
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/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 6b9c340..a990f3e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -24,8 +24,8 @@
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.animation.ValueAnimator;
@@ -145,7 +145,7 @@
OverviewScrim.SCRIM_MULTIPLIER, OVERVIEW_TO_HOME_SCRIM_MULTIPLIER,
PULLBACK_INTERPOLATOR);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
builder.addOnFrameCallback(recentsView::redrawLiveTile);
}
@@ -194,7 +194,7 @@
boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS
|| (velocity < 0 && fling);
if (success) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
RecentsView recentsView = mLauncher.getOverviewPanel();
recentsView.switchToScreenshot(null,
() -> recentsView.finishRecentsAnimation(true /* toRecents */, null));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index c60e257..facfb9d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -126,26 +126,11 @@
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "PortraitStatesTouchController.getTargetState");
- }
if (fromState == ALL_APPS && !isDragTowardPositive) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
- "PortraitStatesTouchController.getTargetState 1");
- }
return NORMAL;
} else if (fromState == OVERVIEW) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
- "PortraitStatesTouchController.getTargetState 2");
- }
return isDragTowardPositive ? OVERVIEW : NORMAL;
} else if (fromState == NORMAL && isDragTowardPositive) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
- "PortraitStatesTouchController.getTargetState 3");
- }
return ALL_APPS;
}
return fromState;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 1bd7fe6..7f2af6b 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -25,7 +25,7 @@
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.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.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
@@ -45,6 +45,7 @@
import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -79,7 +80,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
@@ -104,7 +104,6 @@
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.SwipePipToHomeAnimator;
import com.android.quickstep.util.TransformParams;
-import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -318,7 +317,7 @@
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_FINISH_WITH_NO_END,
this::notifyTransitionCancelled);
- if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (!LIVE_TILE.get()) {
mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
| STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
(b) -> mRecentsView.setRunningTaskHidden(!b));
@@ -353,7 +352,6 @@
mRecentsView = activity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
- addLiveTileOverlay();
mStateCallback.setState(STATE_LAUNCHER_PRESENT);
if (alreadyOnHome) {
@@ -459,7 +457,7 @@
}
private void onDeferredActivityLaunch() {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
mActivityInterface.switchRunningTaskViewToScreenshot(
null, () -> {
mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
@@ -918,26 +916,15 @@
isFling, isCancel);
float endShift = endTarget.isLauncher ? 1 : 0;
final float startShift;
- Interpolator interpolator = DEACCEL;
if (!isFling) {
long expectedDuration = Math.abs(Math.round((endShift - currentShift)
* MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
startShift = currentShift;
- interpolator = endTarget == RECENTS ? ACCEL_DEACCEL : DEACCEL;
} else {
startShift = Utilities.boundToRange(currentShift - velocity.y
* getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);
if (mTransitionDragLength > 0) {
- if (endTarget == RECENTS && !mDeviceState.isFullyGesturalNavMode()) {
- Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
- startShift, endShift, endShift, endVelocity,
- mTransitionDragLength, mContext);
- endShift = overshoot.end;
- interpolator = overshoot.interpolator;
- duration = Utilities.boundToRange(overshoot.duration, MIN_OVERSHOOT_DURATION,
- MAX_SWIPE_DURATION);
- } else {
float distanceToTravel = (endShift - currentShift) * mTransitionDragLength;
// we want the page's snap velocity to approximately match the velocity at
@@ -945,13 +932,9 @@
// derivative of the scroll interpolator at zero, ie. 2.
long baseDuration = Math.round(Math.abs(distanceToTravel / velocity.y));
duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
-
- if (endTarget == RECENTS) {
- interpolator = ACCEL_DEACCEL;
- }
- }
}
}
+ Interpolator interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL;
if (endTarget.isLauncher) {
mInputConsumerProxy.enable();
@@ -1241,13 +1224,6 @@
});
anim.addAnimatorListener(new AnimationSuccessListener() {
@Override
- public void onAnimationStart(Animator animation) {
- if (mActivity != null) {
- removeLiveTileOverlay();
- }
- }
-
- @Override
public void onAnimationSuccess(Animator animator) {
if (mRecentsView != null) {
mRecentsView.post(mRecentsView::resetTaskVisuals);
@@ -1268,7 +1244,7 @@
// In the off chance that the gesture ends before Launcher is started, we should clear
// the callback here so that it doesn't update with the wrong state
mActivity.clearRunOnceOnStartCallback();
- resetLauncherListenersAndOverlays();
+ resetLauncherListeners();
}
if (mGestureState.getEndTarget() != null && !mGestureState.isRunningAnimationToLauncher()) {
cancelCurrentAnimation();
@@ -1351,7 +1327,7 @@
endLauncherTransitionController();
mRecentsView.onGestureAnimationEnd();
- resetLauncherListenersAndOverlays();
+ resetLauncherListeners();
}
private void endLauncherTransitionController() {
@@ -1364,13 +1340,12 @@
}
}
- private void resetLauncherListenersAndOverlays() {
+ private void resetLauncherListeners() {
// Reset the callback for deferred activity launches
- if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (!LIVE_TILE.get()) {
mActivityInterface.setOnDeferredActivityLaunchCallback(null);
}
mActivity.getRootView().setOnApplyWindowInsetsListener(null);
- removeLiveTileOverlay();
}
private void notifyTransitionCancelled() {
@@ -1387,7 +1362,7 @@
protected void switchToScreenshot() {
final int runningTaskId = mGestureState.getRunningTaskId();
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
if (mRecentsAnimationController != null) {
mRecentsAnimationController.getController().setWillFinishToHome(true);
// Update the screenshot of the task
@@ -1456,7 +1431,7 @@
}
private void finishCurrentTransitionToRecents() {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else if (!hasTargets() || mRecentsAnimationController == null) {
// If there are no targets or the animation not started, then there is nothing to finish
@@ -1517,7 +1492,7 @@
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
mRecentsView.onSwipeUpAnimationSuccess();
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler(
appearedTaskTarget -> {
RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
@@ -1594,17 +1569,6 @@
anim.start();
}
- private void addLiveTileOverlay() {
- if (LiveTileOverlay.INSTANCE.attach(mActivity.getRootView().getOverlay())) {
- mRecentsView.setLiveTileOverlayAttached(true);
- }
- }
-
- private void removeLiveTileOverlay() {
- LiveTileOverlay.INSTANCE.detach(mActivity.getRootView().getOverlay());
- mRecentsView.setLiveTileOverlayAttached(false);
- }
-
private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
return app.isNotInRecents
|| app.activityType == ACTIVITY_TYPE_HOME;
@@ -1765,13 +1729,6 @@
}
mTaskViewSimulator.apply(mTransformParams);
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mRecentsAnimationTargets != null) {
- LiveTileOverlay.INSTANCE.update(
- mTaskViewSimulator.getCurrentRect(),
- mTaskViewSimulator.getCurrentCornerRadius());
- LiveTileOverlay.INSTANCE.setRotation(
- mTaskViewSimulator.getOrientationState().getDisplayRotation());
- }
ProtoTracer.INSTANCE.get(mContext).scheduleFrameUpdate();
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 8b0d782..3f3e5ad 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -187,9 +187,6 @@
@Override
public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "switchToRecentsIfVisible");
- }
Launcher launcher = getVisibleLauncher();
if (launcher == null) {
return false;
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index 65847f1..192738f 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
+
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -59,6 +61,8 @@
super.init(context);
+ LIVE_TILE.initialize(context);
+
// Elevate GPU priority for Quickstep and Remote animations.
ThreadedRendererCompat.setContextPriority(
ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 1c5dc4c..2f1538b 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -22,10 +22,12 @@
import android.app.ActivityManager;
import android.os.Build;
import android.os.Process;
+import android.util.Log;
import android.util.SparseBooleanArray;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.LooperExecutor;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -51,6 +53,9 @@
// The list change id, increments as the task list changes in the system
private int mChangeId;
+ // Whether we are currently updating the tasks in the background (up to when the result is
+ // posted back on the main thread)
+ private boolean mLoadingTasksInBackground;
private TaskLoadResult mResultsBg = INVALID_RESULT;
private TaskLoadResult mResultsUi = INVALID_RESULT;
@@ -64,6 +69,11 @@
mActivityManagerWrapper.registerTaskStackListener(this);
}
+ @VisibleForTesting
+ public boolean isLoadingTasksInBackground() {
+ return mLoadingTasksInBackground;
+ }
+
/**
* Fetches the task keys skipping any local cache.
*/
@@ -83,6 +93,10 @@
* @return The change id of the current task list
*/
public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: keysOnly=" + loadKeysOnly
+ + " callback=" + callback);
+ }
final int requestLoadId = mChangeId;
if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
// The list is up to date, send the callback on the next frame,
@@ -90,22 +104,38 @@
if (callback != null) {
// Copy synchronously as the changeId might change by next frame
ArrayList<Task> result = copyOf(mResultsUi);
- mMainThreadExecutor.post(() -> callback.accept(result));
+ mMainThreadExecutor.post(() -> {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: no new tasks");
+ }
+ callback.accept(result);
+ });
}
return requestLoadId;
}
// Kick off task loading in the background
+ mLoadingTasksInBackground = true;
UI_HELPER_EXECUTOR.execute(() -> {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: loading in bg start");
+ }
if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly)) {
mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
}
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: loading in bg end");
+ }
TaskLoadResult loadResult = mResultsBg;
mMainThreadExecutor.execute(() -> {
+ mLoadingTasksInBackground = false;
mResultsUi = loadResult;
if (callback != null) {
ArrayList<Task> result = copyOf(mResultsUi);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: callback w/ bg results");
+ }
callback.accept(result);
}
});
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index d47217b..ba24e6a 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -28,6 +28,8 @@
import android.os.Process;
import android.os.UserHandle;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
@@ -102,6 +104,14 @@
}
/**
+ * @return Whether the task list is currently updating in the background
+ */
+ @VisibleForTesting
+ public boolean isLoadingTasksInBackground() {
+ return mTaskList.isLoadingTasksInBackground();
+ }
+
+ /**
* Finds and returns the task key associated with the given task id.
*
* @param callback The callback to receive the task key if it is found or null. This is always
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index ca73041..f4b8b62 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -94,13 +94,7 @@
mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT,
mTaskViewSimulator.getOrientationState().getOrientationHandler());
-
- if (mDeviceState.isFullyGesturalNavMode()) {
- // We can drag all the way to the top of the screen.
- mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
- } else {
- mDragLengthFactor = 1 + AnimatorControllerWithResistance.TWO_BUTTON_EXTRA_DRAG_FACTOR;
- }
+ mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2);
mTaskViewSimulator.addAppToOverviewAnim(pa, LINEAR);
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 64d05e1..5668817 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -21,11 +21,11 @@
import android.app.PictureInPictureParams;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@@ -37,6 +37,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISplitScreenListener;
+import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
@@ -516,14 +517,40 @@
}
@Override
- public void startIntent(PendingIntent intent, int stage, int position, Bundle options) {
+ public void startIntent(PendingIntent intent, Intent fillInIntent, int stage,
+ int position, Bundle options) {
if (mSystemUiProxy != null) {
try {
- mSystemUiProxy.startIntent(intent, stage, position, options);
+ mSystemUiProxy.startIntent(intent, fillInIntent, stage, position,
+ options);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntent");
}
}
}
+ @Override
+ public void removeFromSideStage(int taskId) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.removeFromSideStage(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call removeFromSideStage");
+ }
+ }
+ }
+
+ /**
+ * Sets listener to get callbacks when launching a task.
+ */
+ @Override
+ public void setStartingWindowListener(IStartingWindowListener listener) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.setStartingWindowListener(listener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call setStartingWindowListener", e);
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 0d2c42e..8636130 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -18,7 +18,7 @@
import static android.view.Surface.ROTATION_0;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
@@ -163,7 +163,7 @@
* @param callback callback to run, after switching to screenshot
*/
public void endLiveTileMode(@NonNull Runnable callback) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView();
recentsView.switchToScreenshot(
() -> recentsView.finishRecentsAnimation(true /* toRecents */, callback));
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index cd4f52f..17822e6 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -23,8 +23,8 @@
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.clampToProgress;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -139,7 +139,7 @@
boolean isRunningTask = v.isRunningTask();
TransformParams params = null;
TaskViewSimulator tsv = null;
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask) {
+ if (LIVE_TILE.get() && isRunningTask) {
params = v.getRecentsView().getLiveTileParams();
tsv = v.getRecentsView().getLiveTileTaskViewSimulator();
}
@@ -159,8 +159,7 @@
boolean isQuickSwitch = v.isEndQuickswitchCuj();
v.setEndQuickswitchCuj(false);
- boolean inLiveTileMode =
- ENABLE_QUICKSTEP_LIVE_TILE.get() && v.getRecentsView().getRunningTaskIndex() != -1;
+ boolean inLiveTileMode = LIVE_TILE.get() && v.getRecentsView().getRunningTaskIndex() != -1;
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets,
inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
@@ -181,6 +180,7 @@
boolean parallaxCenterAndAdjacentTask =
taskIndex != recentsView.getCurrentPage() && !(dp.isTablet
&& FeatureFlags.ENABLE_OVERVIEW_GRID.get());
+ float gridTranslationSecondary = recentsView.getGridTranslationSecondary(taskIndex);
int startScroll = recentsView.getScrollOffset(taskIndex);
TaskViewSimulator topMostSimulator = null;
@@ -197,6 +197,8 @@
tsv.setPreview(targets.apps[targets.apps.length - 1]);
tsv.fullScreenProgress.value = 0;
tsv.recentsViewScale.value = 1;
+ tsv.gridProgress.value = 1;
+ tsv.gridTranslationSecondary.value = gridTranslationSecondary;
tsv.setScroll(startScroll);
// Fade in the task during the initial 20% of the animation
@@ -209,6 +211,7 @@
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.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
TaskViewSimulator finalTsv = tsv;
@@ -341,7 +344,7 @@
};
}
pa.add(launcherAnim);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1) {
+ if (LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1) {
pa.addOnFrameCallback(recentsView::redrawLiveTile);
}
anim.play(pa.buildAnim());
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 27c7ade..fc805d0 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -21,9 +21,9 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -687,8 +687,7 @@
runningComponent != null && runningComponent.equals(homeComponent);
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()
- && gestureState.getActivityInterface().isInLiveTileMode()) {
+ if (LIVE_TILE.get() && gestureState.getActivityInterface().isInLiveTileMode()) {
return createOverviewInputConsumer(
previousGestureState, gestureState, event, forceOverviewInputConsumer);
} else if (gestureState.getRunningTask() == null) {
@@ -744,8 +743,7 @@
|| previousGestureState.isRunningAnimationToLauncher()
|| (ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
&& forceOverviewInputConsumer)
- || (ENABLE_QUICKSTEP_LIVE_TILE.get())
- && gestureState.getActivityInterface().isInLiveTileMode()) {
+ || (LIVE_TILE.get()) && gestureState.getActivityInterface().isInLiveTileMode()) {
return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
false /* startingInActivityBounds */);
} else {
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 8f2356c..13f6137 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -24,9 +24,11 @@
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
+import android.util.Log;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
+import com.android.launcher3.testing.TestProtocol;
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsActivity;
@@ -120,6 +122,10 @@
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == mRunningTaskId && !tasks.isEmpty()) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED,
+ "FallbackRecentsView.applyLoadPlan: running task is home");
+ }
// Check if the task list has running task
boolean found = false;
for (Task t : tasks) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index aad70c4..cee3363 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -15,7 +15,7 @@
*/
package com.android.quickstep.inputconsumers;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.view.KeyEvent;
@@ -99,7 +99,7 @@
@Override
public void onKeyEvent(KeyEvent ev) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
mActivity.dispatchKeyEvent(ev);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index deb70e0..7f94839 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -38,7 +37,6 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.LauncherActivityInterface;
-import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.views.RecentsView;
/**
@@ -49,12 +47,6 @@
*/
public class AnimatorControllerWithResistance {
- /**
- * How much farther we can drag past overview in 2-button mode, as a factor of the distance
- * it takes to drag from an app to overview.
- */
- public static final float TWO_BUTTON_EXTRA_DRAG_FACTOR = 0.25f;
-
private enum RecentsResistanceParams {
FROM_APP(0.75f, 0.5f, 1f),
FROM_OVERVIEW(1f, 0.75f, 0.5f);
@@ -161,12 +153,6 @@
LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect,
orientationHandler);
long distanceToCover = startRect.bottom;
- boolean isTwoButtonMode = SysUINavigationMode.getMode(params.context) == TWO_BUTTONS;
- if (isTwoButtonMode) {
- // We can only drag a small distance past overview, not to the top of the screen.
- distanceToCover = (long)
- ((params.dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR);
- }
PendingAnimation resistAnim = params.resistAnim != null
? params.resistAnim
: new PendingAnimation(distanceToCover * 2);
@@ -178,43 +164,35 @@
/ (params.dp.heightPx - startRect.bottom);
// This is what the scale would be at the end of the drag if we didn't apply resistance.
float endScale = params.startScale - prevScaleRate * distanceToCover;
- final TimeInterpolator scaleInterpolator;
- if (isTwoButtonMode) {
- // We are bounded by the distance of the drag, so we don't need to apply resistance.
- scaleInterpolator = LINEAR;
- } else {
- // Create an interpolator that resists the scale so the scale doesn't get smaller than
- // RECENTS_SCALE_MAX_RESIST.
- float startResist = Utilities.getProgress(params.resistanceParams.scaleStartResist,
- params.startScale, endScale);
- float maxResist = Utilities.getProgress(params.resistanceParams.scaleMaxResist,
- params.startScale, endScale);
- scaleInterpolator = t -> {
- if (t < startResist) {
- return t;
- }
- float resistProgress = Utilities.getProgress(t, startResist, 1);
- resistProgress = RECENTS_SCALE_RESIST_INTERPOLATOR.getInterpolation(resistProgress);
- return startResist + resistProgress * (maxResist - startResist);
- };
- }
+ // Create an interpolator that resists the scale so the scale doesn't get smaller than
+ // RECENTS_SCALE_MAX_RESIST.
+ float startResist = Utilities.getProgress(params.resistanceParams.scaleStartResist,
+ params.startScale, endScale);
+ float maxResist = Utilities.getProgress(params.resistanceParams.scaleMaxResist,
+ params.startScale, endScale);
+ final TimeInterpolator scaleInterpolator = t -> {
+ if (t < startResist) {
+ return t;
+ }
+ float resistProgress = Utilities.getProgress(t, startResist, 1);
+ resistProgress = RECENTS_SCALE_RESIST_INTERPOLATOR.getInterpolation(resistProgress);
+ return startResist + resistProgress * (maxResist - startResist);
+ };
resistAnim.addFloat(params.scaleTarget, params.scaleProperty, params.startScale, endScale,
scaleInterpolator);
- if (!isTwoButtonMode) {
- // Compute where the task view would be based on the end scale, if we didn't translate.
- RectF endRectF = new RectF(startRect);
- Matrix temp = new Matrix();
- temp.setScale(params.resistanceParams.scaleMaxResist,
- params.resistanceParams.scaleMaxResist, pivot.x, pivot.y);
- temp.mapRect(endRectF);
- // Translate such that the task view touches the top of the screen when drag does.
- float endTranslation = endRectF.top
- * orientationHandler.getSecondaryTranslationDirectionFactor()
- * params.resistanceParams.translationFactor;
- resistAnim.addFloat(params.translationTarget, params.translationProperty,
- params.startTranslation, endTranslation, RECENTS_TRANSLATE_RESIST_INTERPOLATOR);
- }
+ // Compute where the task view would be based on the end scale.
+ RectF endRectF = new RectF(startRect);
+ Matrix temp = new Matrix();
+ temp.setScale(params.resistanceParams.scaleMaxResist,
+ params.resistanceParams.scaleMaxResist, pivot.x, pivot.y);
+ temp.mapRect(endRectF);
+ // Translate such that the task view touches the top of the screen when drag does.
+ float endTranslation = endRectF.top
+ * orientationHandler.getSecondaryTranslationDirectionFactor()
+ * params.resistanceParams.translationFactor;
+ resistAnim.addFloat(params.translationTarget, params.translationProperty,
+ params.startTranslation, endTranslation, RECENTS_TRANSLATE_RESIST_INTERPOLATOR);
return resistAnim;
}
diff --git a/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java b/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
new file mode 100644
index 0000000..60c7add
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
@@ -0,0 +1,58 @@
+/*
+ * 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 static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+
+import android.content.Context;
+
+import com.android.quickstep.SysUINavigationMode;
+
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/** A feature flag that listens to navigation mode changes. */
+public class NavigationModeFeatureFlag implements
+ SysUINavigationMode.NavigationModeChangeListener {
+
+ public static final NavigationModeFeatureFlag LIVE_TILE = new NavigationModeFeatureFlag(
+ ENABLE_QUICKSTEP_LIVE_TILE::get, mode -> mode.hasGestures);
+
+ private final Supplier<Boolean> mBasePredicate;
+ private final Predicate<SysUINavigationMode.Mode> mModePredicate;
+ private boolean mSupported;
+
+ private NavigationModeFeatureFlag(Supplier<Boolean> basePredicate,
+ Predicate<SysUINavigationMode.Mode> modePredicate) {
+ mBasePredicate = basePredicate;
+ mModePredicate = modePredicate;
+ }
+
+ public boolean get() {
+ return mBasePredicate.get() && mSupported;
+ }
+
+ public void initialize(Context context) {
+ onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context).getMode());
+ SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
+ }
+
+ @Override
+ public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
+ mSupported = mModePredicate.test(newMode);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 8c98480..9537247 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -16,9 +16,9 @@
package com.android.quickstep.util;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
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;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
@@ -97,6 +97,7 @@
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();
@@ -316,9 +317,10 @@
mMatrix.postScale(scale, scale, mIsRecentsRtl ? 0 : taskWidth, 0);
float taskWidthDiff = taskWidth * (1 - gridScale);
float taskWidthOffset = mIsRecentsRtl ? taskWidthDiff : -taskWidthDiff;
- float translationPrimary = Utilities.mapRange(interpolatedGridProgress, 0, taskWidthOffset);
mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
- translationPrimary);
+ Utilities.mapRange(interpolatedGridProgress, 0, taskWidthOffset));
+ mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
+ Utilities.mapRange(interpolatedGridProgress, 0, gridTranslationSecondary.value));
// Apply TaskView matrix: translate, scroll
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
@@ -352,7 +354,7 @@
.withCornerRadius(getCurrentCornerRadius())
.withShadowRadius(app.isTranslucent ? 0 : params.getShadowRadius());
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
+ if (LIVE_TILE.get() && params.getRecentsSurface() != null) {
// When relativeLayer = 0, it reverts the surfaces back to the original order.
builder.withRelativeLayerTo(params.getRecentsSurface(),
mDrawsBelowRecents ? Integer.MIN_VALUE : 0);
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 84218fd..d99f707 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -23,7 +23,7 @@
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
@@ -95,7 +95,7 @@
public void startHome() {
Runnable onReachedHome = () -> mActivity.getStateManager().goToState(NORMAL, false);
OverviewToHomeAnim overviewToHomeAnim = new OverviewToHomeAnim(mActivity, onReachedHome);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
switchToScreenshot(null,
() -> finishRecentsAnimation(true /* toRecents */,
() -> overviewToHomeAnim.animateWithVelocity(0)));
diff --git a/quickstep/src/com/android/quickstep/views/LiveTileOverlay.java b/quickstep/src/com/android/quickstep/views/LiveTileOverlay.java
deleted file mode 100644
index 8210ab0..0000000
--- a/quickstep/src/com/android/quickstep/views/LiveTileOverlay.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package com.android.quickstep.views;
-
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
-
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.util.FloatProperty;
-import android.view.ViewOverlay;
-
-import com.android.launcher3.anim.Interpolators;
-import com.android.quickstep.util.RecentsOrientedState.SurfaceRotation;
-
-public class LiveTileOverlay extends Drawable {
-
- private static final long ICON_ANIM_DURATION = 120;
-
- private static final FloatProperty<LiveTileOverlay> PROGRESS =
- new FloatProperty<LiveTileOverlay>("progress") {
- @Override
- public void setValue(LiveTileOverlay liveTileOverlay, float progress) {
- liveTileOverlay.setIconAnimationProgress(progress);
- }
-
- @Override
- public Float get(LiveTileOverlay liveTileOverlay) {
- return liveTileOverlay.mIconAnimationProgress;
- }
- };
-
- public static final LiveTileOverlay INSTANCE = new LiveTileOverlay();
-
- private final Paint mPaint = new Paint();
- private final RectF mCurrentRect = new RectF();
- private final Rect mBoundsRect = new Rect();
-
- private @SurfaceRotation int mRotation = ROTATION_0;
-
- private float mCornerRadius;
- private Drawable mIcon;
- private Animator mIconAnimator;
-
- private float mIconAnimationProgress = 0f;
- private boolean mIsAttached;
-
- private LiveTileOverlay() {
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
- }
-
- public void update(RectF currentRect, float cornerRadius) {
- invalidateSelf();
-
- mCurrentRect.set(currentRect);
- mCornerRadius = cornerRadius;
-
- mCurrentRect.roundOut(mBoundsRect);
- setBounds(mBoundsRect);
- invalidateSelf();
- }
-
- public void update(float left, float top, float right, float bottom) {
- mCurrentRect.set(left, top, right, bottom);
- }
-
- public void setRotation(@SurfaceRotation int rotation) {
- mRotation = rotation;
- }
-
- public void setIcon(Drawable icon) {
- mIcon = icon;
- }
-
- // TODO: consider cleaning this up and drawing icon in another way. Previously we place app
- // below launcher during the initial swipe up and render the icon in this live tile overlay.
- // However, this resulted in a bunch of touch input issues caused by Launcher getting the input
- // events during transition (to overview / to another app (quick switch). So now our new
- // solution places app on top in live tile until it fully settles in Overview.
- public void startIconAnimation() {
- if (mIconAnimator != null) {
- mIconAnimator.cancel();
- }
- // This animator must match the icon part of {@link TaskView#FOCUS_TRANSITION} animation.
- mIconAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 1);
- mIconAnimator.setDuration(ICON_ANIM_DURATION).setInterpolator(LINEAR);
- mIconAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mIconAnimator = null;
- }
- });
- mIconAnimator.start();
- }
-
- public float cancelIconAnimation() {
- if (mIconAnimator != null) {
- mIconAnimator.cancel();
- }
- return mIconAnimationProgress;
- }
-
- @Override
- public void draw(Canvas canvas) {
- canvas.drawRoundRect(mCurrentRect, mCornerRadius, mCornerRadius, mPaint);
- if (mIcon != null && mIconAnimationProgress > 0f) {
- canvas.save();
- float scale = Interpolators.clampToProgress(FAST_OUT_SLOW_IN, 0f,
- 1f).getInterpolation(mIconAnimationProgress);
-
- int iconRadius = mIcon.getBounds().width() / 2;
- float dx = 0;
- float dy = 0;
-
- switch (mRotation) {
- case ROTATION_0:
- dx = mCurrentRect.centerX() - iconRadius * scale;
- dy = mCurrentRect.top - iconRadius * scale;
- break;
- case ROTATION_90:
- dx = mCurrentRect.right - iconRadius * scale;
- dy = mCurrentRect.centerY() - iconRadius * scale;
- break;
- case ROTATION_270:
- dx = mCurrentRect.left - iconRadius * scale;
- dy = mCurrentRect.centerY() - iconRadius * scale;
- break;
- case ROTATION_180:
- dx = mCurrentRect.centerX() - iconRadius * scale;
- dy = mCurrentRect.bottom - iconRadius * scale;
- break;
- }
-
- int rotationDegrees = mRotation * 90;
- if (mRotation == ROTATION_90 || mRotation == ROTATION_270) {
- canvas.rotate(rotationDegrees, dx + iconRadius, dy + iconRadius);
- }
- canvas.translate(dx, dy);
- canvas.scale(scale, scale);
- mIcon.draw(canvas);
- canvas.restore();
- }
- }
-
- @Override
- public void setAlpha(int i) { }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) { }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- public boolean attach(ViewOverlay overlay) {
- if (overlay != null && !mIsAttached) {
- overlay.add(this);
- mIsAttached = true;
- return true;
- }
-
- return false;
- }
-
- public void detach(ViewOverlay overlay) {
- if (overlay != null) {
- overlay.remove(this);
- mIsAttached = false;
- }
- }
-
- private void setIconAnimationProgress(float progress) {
- mIconAnimationProgress = progress;
- invalidateSelf();
- }
-}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e20540c..f20ca82 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -35,7 +35,6 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
@@ -43,6 +42,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
@@ -72,6 +72,7 @@
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -104,6 +105,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
import com.android.launcher3.util.DynamicResource;
@@ -420,7 +422,6 @@
private boolean mShowEmptyMessage;
private OnEmptyMessageUpdatedListener mOnEmptyMessageUpdatedListener;
private Layout mEmptyTextLayout;
- private boolean mLiveTileOverlayAttached;
// Keeps track of the index where the first TaskView should be
private int mTaskViewStartIndex = 0;
@@ -561,7 +562,7 @@
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
- if (visibility != VISIBLE && ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (visibility != VISIBLE && LIVE_TILE.get()) {
finishRecentsAnimation(true /* toRecents */, null);
}
updateTaskStackListenerState();
@@ -823,6 +824,12 @@
}
protected void applyLoadPlan(ArrayList<Task> tasks) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "applyLoadPlan: taskCount=" + tasks.size());
+ for (Task t : tasks) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "\t" + t);
+ }
+ }
if (mPendingAnimation != null) {
mPendingAnimation.addEndListener(success -> applyLoadPlan(tasks));
return;
@@ -884,12 +891,21 @@
resetTaskVisuals();
onTaskStackUpdated();
updateEnabledOverlays();
+
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "applyLoadPlan: taskViewCount="
+ + getTaskViewCount());
+ }
}
private boolean isModal() {
return mTaskModalness > 0;
}
+ public boolean isLoadingTasks() {
+ return mModel.isLoadingTasksInBackground();
+ }
+
private void removeTasksViewsAndClearAllButton() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
removeView(getTaskViewAt(i));
@@ -900,6 +916,12 @@
}
public int getTaskViewCount() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "getTaskViewCount:"
+ + " numChildren=" + getChildCount()
+ + " start=" + mTaskViewStartIndex
+ + " clearAll=" + indexOfChild(mClearAllButton));
+ }
int taskViewCount = getChildCount() - mTaskViewStartIndex;
if (indexOfChild(mClearAllButton) != -1) {
taskViewCount--;
@@ -922,16 +944,14 @@
taskView.setModalness(mTaskModalness);
}
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
// Since we reuse the same mLiveTileTaskViewSimulator in the RecentsView, we need
// to reset the params after it settles in Overview from swipe up so that we don't
// render with obsolete param values.
+ mLiveTileTaskViewSimulator.taskPrimaryTranslation.value = 0;
+ mLiveTileTaskViewSimulator.taskSecondaryTranslation.value = 0;
mLiveTileTaskViewSimulator.fullScreenProgress.value = 0;
mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
-
- // Reset the live tile rect
- DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- LiveTileOverlay.INSTANCE.update(0, 0, deviceProfile.widthPx, deviceProfile.heightPx);
}
if (mRunningTaskTileHidden) {
setRunningTaskHidden(mRunningTaskTileHidden);
@@ -1042,7 +1062,7 @@
mModel.getThumbnailCache().getHighResLoadingState().setFlingingFast(isFlingingFast);
mLiveTileTaskViewSimulator.setScroll(getScrollOffset());
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile
+ if (LIVE_TILE.get() && mEnableDrawingLiveTile
&& mLiveTileParams.getTargetSet() != null) {
redrawLiveTile();
}
@@ -1264,10 +1284,7 @@
*/
public void onSwipeUpAnimationSuccess() {
if (getRunningTaskView() != null) {
- float startProgress = ENABLE_QUICKSTEP_LIVE_TILE.get() && mLiveTileOverlayAttached
- ? LiveTileOverlay.INSTANCE.cancelIconAnimation()
- : 0f;
- animateUpRunningTaskIconScale(startProgress);
+ animateUpRunningTaskIconScale(0f);
}
setSwipeDownShouldLaunchApp(true);
}
@@ -1326,7 +1343,7 @@
setOnScrollChangeListener(null);
setEnableFreeScroll(true);
setEnableDrawingLiveTile(true);
- if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (!LIVE_TILE.get()) {
setRunningTaskViewShowScreenshot(true);
}
setRunningTaskHidden(false);
@@ -1418,7 +1435,7 @@
}
private void setRunningTaskViewShowScreenshot(boolean showScreenshot) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
TaskView runningTaskView = getRunningTaskView();
if (runningTaskView != null) {
runningTaskView.setShowScreenshot(showScreenshot);
@@ -1824,7 +1841,7 @@
anim.addOnFrameCallback(this::updateCurveProperties);
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && getRunningTaskView() == taskView) {
+ if (LIVE_TILE.get() && getRunningTaskView() == taskView) {
anim.addOnFrameCallback(() -> {
mLiveTileTaskViewSimulator.taskSecondaryTranslation.value =
mOrientationHandler.getSecondaryValue(
@@ -1843,7 +1860,7 @@
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && taskView.isRunningTask() && success) {
+ if (LIVE_TILE.get() && taskView.isRunningTask() && success) {
finishRecentsAnimation(true /* toHome */, () -> onEnd(success));
} else {
onEnd(success);
@@ -2390,7 +2407,7 @@
anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex),
mOrientationHandler.getPrimaryViewTranslate(), primaryTranslation));
int runningTaskIndex = recentsView.getRunningTaskIndex();
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && runningTaskIndex != -1
+ if (LIVE_TILE.get() && runningTaskIndex != -1
&& runningTaskIndex != taskIndex) {
anim.play(ObjectAnimator.ofFloat(
recentsView.getLiveTileTaskViewSimulator().taskPrimaryTranslation,
@@ -2467,7 +2484,7 @@
mPendingAnimation = new PendingAnimation(duration);
mPendingAnimation.add(anim);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
mLiveTileTaskViewSimulator.addOverviewToAppAnim(mPendingAnimation, interpolator);
mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
}
@@ -2479,7 +2496,7 @@
tv.notifyTaskLaunchFailed(TAG);
}
};
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
finishRecentsAnimation(false /* toRecents */, null);
onLaunchResult.accept(true /* success */);
} else {
@@ -2589,16 +2606,6 @@
}
}
- public void setLiveTileOverlayAttached(boolean liveTileOverlayAttached) {
- mLiveTileOverlayAttached = liveTileOverlayAttached;
- }
-
- public void updateLiveTileIcon(Drawable icon) {
- if (mLiveTileOverlayAttached) {
- LiveTileOverlay.INSTANCE.setIcon(icon);
- }
- }
-
public void finishRecentsAnimation(boolean toRecents, Runnable onFinishComplete) {
if (mRecentsAnimationController == null) {
if (onFinishComplete != null) {
@@ -2729,7 +2736,7 @@
}
/**
- * @return How many pixels the page is offset on the currently laid out dominant axis.
+ * Returns how many pixels the page is offset on the currently laid out dominant axis.
*/
public int getScrollOffset(int pageIndex) {
if (pageIndex == -1) {
@@ -2745,6 +2752,20 @@
return getScrollForPage(pageIndex) - scroll;
}
+ /**
+ * Returns how many pixels the task is offset on the currently laid out secondary axis
+ * according to {@link #mGridProgress}.
+ */
+ public float getGridTranslationSecondary(int pageIndex) {
+ TaskView taskView = getTaskViewAtByAbsoluteIndex(pageIndex);
+ if (taskView == null) {
+ return 0;
+ }
+
+ return mOrientationHandler.getSecondaryValue(taskView.getGridTranslationX(),
+ taskView.getGridTranslationY());
+ }
+
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
if (navbarRotation == 0) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index f477ca7..2315147 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -16,7 +16,7 @@
package com.android.quickstep.views;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
import android.animation.Animator;
@@ -183,7 +183,7 @@
LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams();
mTaskView.getPagedOrientationHandler().setLayoutParamsForTaskMenuOptionItem(lp);
menuOptionView.setOnClickListener(view -> {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
RecentsView recentsView = mTaskView.getRecentsView();
recentsView.switchToScreenshot(null,
() -> recentsView.finishRecentsAnimation(true /* toRecents */,
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index f2f4bc1..4c21745 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -19,7 +19,7 @@
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
import android.content.Context;
@@ -319,7 +319,7 @@
public void drawOnCanvas(Canvas canvas, float x, float y, float width, float height,
float cornerRadius) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (LIVE_TILE.get()) {
if (mTask != null && getTaskView().isRunningTask() && !getTaskView().showScreenshot()) {
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint);
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius,
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 20a8444..0cf7261 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -35,10 +35,10 @@
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -308,7 +308,7 @@
if (getTask() == null) {
return;
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
+ if (LIVE_TILE.get() && isRunningTask()) {
if (!mIsClickableAsLiveTile) {
return;
}
@@ -559,9 +559,6 @@
mIconLoadRequest = iconCache.updateIconInBackground(mTask,
(task) -> {
setIcon(task.icon);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
- getRecentsView().updateLiveTileIcon(task.icon);
- }
mDigitalWellBeingToast.initialize(mTask);
});
} else {
@@ -919,11 +916,19 @@
applyTranslationX();
}
+ public float getGridTranslationX() {
+ return mGridTranslationX;
+ }
+
public void setGridTranslationY(float gridTranslationY) {
mGridTranslationY = gridTranslationY;
applyTranslationY();
}
+ public float getGridTranslationY() {
+ return mGridTranslationY;
+ }
+
public void setGridOffsetTranslationX(float gridOffsetTranslationX) {
mGridOffsetTranslationX = gridOffsetTranslationX;
applyTranslationX();
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 2e7e6e0..713fd07 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -42,6 +42,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.RemoteException;
+import android.util.Log;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -55,6 +56,7 @@
import com.android.launcher3.tapl.OverviewTask;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.quickstep.views.RecentsView;
@@ -172,9 +174,15 @@
protected <T> T getFromRecents(Function<RecentsActivity, T> f) {
if (!TestHelpers.isInLauncherProcess()) return null;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "getFromRecents");
+ }
Object[] result = new Object[1];
Wait.atMost("Failed to get from recents", () -> MAIN_EXECUTOR.submit(() -> {
RecentsActivity activity = RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "activity=" + activity);
+ }
if (activity == null) {
return false;
}
@@ -200,8 +208,13 @@
() -> mLauncher.getRecentTasks().size() >= 3, DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
BaseOverview overview = mLauncher.getBackground().switchToOverview();
- executeOnRecents(recents ->
- assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3));
+ executeOnRecents(recents -> {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.GET_RECENTS_FAILED, "isLoading=" +
+ recents.<RecentsView>getOverviewPanel().isLoadingTasks());
+ }
+ assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3);
+ });
// Test flinging forward and backward.
overview.flingForward();
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index faff10c..041e007 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -52,7 +52,7 @@
android:id="@+id/app_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- tools:text="n widgets" />
+ tools:text="m widgets, n shortcuts" />
</LinearLayout>
diff --git a/res/layout/widgets_scroll_container.xml b/res/layout/widgets_scroll_container.xml
deleted file mode 100644
index fc509d1..0000000
--- a/res/layout/widgets_scroll_container.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-
-<HorizontalScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/widgets_scroll_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/colorPrimaryDark"
- android:scrollbars="none">
- <LinearLayout
- android:id="@+id/widgets_cell_list"
- style="@style/TextTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="0dp"
- android:paddingEnd="0dp"
- android:orientation="horizontal"
- android:showDividers="none"/>
-</HorizontalScrollView>
\ No newline at end of file
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index 1f401c4..ec07591 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -1,5 +1,4 @@
<resources>
- <bool name="config_largeHeap">true</bool>
<!-- All Apps & Widgets -->
<!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 73f9e53..44b5ee7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -52,11 +52,22 @@
<string name="add_item_request_drag_hint">Touch & hold to place manually</string>
<!-- Button label to automatically add icon on home screen [CHAR_LIMIT=50] -->
<string name="place_automatically">Add automatically</string>
- <!-- Label for showing the number of widgets an app has in the full widgets picker. [CHAR_LIMIT=25] -->
- <plurals name="widgets_tray_subtitle">
- <item quantity="one"><xliff:g id="widget_count" example="1">%1$d</xliff:g> widget</item>
- <item quantity="other"><xliff:g id="widget_count" example="2">%1$d</xliff:g> widgets</item>
+ <!-- Label for showing the number of widgets an app has in the full widgets picker.
+ [CHAR_LIMIT=25] -->
+ <plurals name="widgets_count">
+ <item quantity="one"><xliff:g id="widgets_count" example="1">%1$d</xliff:g> widget</item>
+ <item quantity="other"><xliff:g id="widgets_count" example="2">%1$d</xliff:g> widgets</item>
</plurals>
+ <!-- Label for showing the number of shortcut an app has in the full widgets picker.
+ [CHAR_LIMIT=25] -->
+ <plurals name="shortcuts_count">
+ <item quantity="one"><xliff:g id="shortcuts_count" example="1">%1$d</xliff:g> shortcut</item>
+ <item quantity="other"><xliff:g id="shortcuts_count" example="2">%1$d</xliff:g> shortcuts</item>
+ </plurals>
+ <!-- Label for showing both the number of widgets and shortcuts an app has in the full widgets
+ picker. [CHAR_LIMIT=50] -->
+ <string name="widgets_and_shortcuts_count"><xliff:g id="widgets_count" example="5 widgets">%1$s</xliff:g>, <xliff:g id="shortcuts_count" example="1 shortcut">%2$s</xliff:g></string>
+
<!-- Text for both the tile of a popup view, which shows all available widgets installed on
the device, and the text of a button, which opens this popup view. [CHAR LIMIT=30]-->
<string name="widget_button_text">Widgets</string>
diff --git a/robolectric_tests/Android.bp b/robolectric_tests/Android.bp
new file mode 100644
index 0000000..c738df9
--- /dev/null
+++ b/robolectric_tests/Android.bp
@@ -0,0 +1,46 @@
+// 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.
+
+//
+// Launcher Robolectric test target.
+//
+// "robolectric_android-all-stub", not needed, we write our own stubs
+android_robolectric_test {
+ name: "LauncherRoboTests",
+ srcs: [
+ "src/**/*.java",
+ ],
+ java_resource_dirs: [
+ "resources",
+ "res",
+ "config",
+ ],
+ static_libs: [
+ "truth-prebuilt",
+ "Launcher3TestCommon",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "mockito-robolectric-prebuilt",
+ ],
+ //robolectric_prebuilt_version: "4.4",
+ libs: [
+ "platform-robolectric-4.4-prebuilt",
+ ],
+ instrumentation_for: "Launcher3",
+
+ test_options: {
+ timeout: 36000,
+ },
+}
+
diff --git a/robolectric_tests/Android.mk b/robolectric_tests/Android.mk
deleted file mode 100644
index 405a458..0000000
--- a/robolectric_tests/Android.mk
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) 2018 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.
-
-#############################################
-# Launcher Robolectric test target. #
-#############################################
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := LauncherRoboTests
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-
-LOCAL_SDK_VERSION := system_current
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-java-files-under, ../tests/src_common)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.runner \
- androidx.test.rules \
- mockito-robolectric-prebuilt \
- truth-prebuilt
-LOCAL_JAVA_LIBRARIES := \
- platform-robolectric-4.3.1-prebuilt
-
-LOCAL_JAVA_RESOURCE_DIRS := resources config
-
-LOCAL_INSTRUMENTATION_FOR := Launcher3
-LOCAL_MODULE_TAGS := optional
-
-# Generate test_config.properties
-include external/robolectric-shadows/gen_test_config.mk
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-############################################
-# Target to run the previous target. #
-############################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunLauncherRoboTests
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-LOCAL_SDK_VERSION := system_current
-LOCAL_JAVA_LIBRARIES := LauncherRoboTests
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_TEST_PACKAGE := Launcher3
-LOCAL_INSTRUMENT_SOURCE_DIRS := packages/apps/Launcher3/src
-
-LOCAL_ROBOTEST_TIMEOUT := 36000
-
-include prebuilts/misc/common/robolectric/4.4/run_robotests.mk
diff --git a/robolectric_tests/config/robolectric.properties b/robolectric_tests/config/robolectric.properties
index 936ce12..1b170e1 100644
--- a/robolectric_tests/config/robolectric.properties
+++ b/robolectric_tests/config/robolectric.properties
@@ -1,4 +1,5 @@
sdk=29
+
shadows= \
com.android.launcher3.shadows.LShadowAppPredictionManager \
com.android.launcher3.shadows.LShadowAppWidgetManager \
diff --git a/robolectric_tests/src/com/android/launcher3/util/SettingsCacheTest.java b/robolectric_tests/unstaged/SettingsCacheTest.java
similarity index 100%
rename from robolectric_tests/src/com/android/launcher3/util/SettingsCacheTest.java
rename to robolectric_tests/unstaged/SettingsCacheTest.java
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index a813275..3b28d4d 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -12,12 +12,11 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Point;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.util.SizeF;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -368,7 +367,7 @@
public static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
int spanX, int spanY) {
- List<PointF> sizes = getWidgetSizes(launcher, spanX, spanY);
+ List<SizeF> sizes = getWidgetSizes(launcher, spanX, spanY);
if (ATLEAST_S) {
widgetView.updateAppWidgetSize(new Bundle(), sizes);
} else {
@@ -378,43 +377,25 @@
}
}
- private static PointF getWidgetSize(Context context, Point cellSize, int spanX, int spanY,
+ private static SizeF getWidgetSize(Context context, Point cellSize, int spanX, int spanY,
int borderSpacing) {
final float density = context.getResources().getDisplayMetrics().density;
final float hBorderSpacing = (spanX - 1) * borderSpacing;
final float vBorderSpacing = (spanY - 1) * borderSpacing;
- PointF widgetSize = new PointF();
- widgetSize.x = ((spanX * cellSize.x) + hBorderSpacing) / density;
- widgetSize.y = ((spanY * cellSize.y) + vBorderSpacing) / density;
- return widgetSize;
- }
-
- /** Returns the actual widget size given its span. */
- public static PointF getWidgetSize(Context context, int spanX, int spanY) {
- final Point[] cellSize = CELL_SIZE.get(context);
- final int[] borderSpacing = BORDER_SPACING_SIZE.get(context);
- if (isLandscape(context)) {
- return getWidgetSize(context, cellSize[0], spanX, spanY, borderSpacing[0]);
- }
- return getWidgetSize(context, cellSize[1], spanX, spanY, borderSpacing[1]);
- }
-
- /** Returns true if the screen is in landscape mode. */
- private static boolean isLandscape(Context context) {
- return context.getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_LANDSCAPE;
+ return new SizeF(((spanX * cellSize.x) + hBorderSpacing) / density,
+ ((spanY * cellSize.y) + vBorderSpacing) / density);
}
/** Returns the list of sizes for a widget of given span, in dp. */
- public static ArrayList<PointF> getWidgetSizes(Context context, int spanX, int spanY) {
+ public static ArrayList<SizeF> getWidgetSizes(Context context, int spanX, int spanY) {
final Point[] cellSize = CELL_SIZE.get(context);
final int[] borderSpacing = BORDER_SPACING_SIZE.get(context);
- PointF landSize = getWidgetSize(context, cellSize[0], spanX, spanY, borderSpacing[0]);
- PointF portSize = getWidgetSize(context, cellSize[1], spanX, spanY, borderSpacing[1]);
+ SizeF landSize = getWidgetSize(context, cellSize[0], spanX, spanY, borderSpacing[0]);
+ SizeF portSize = getWidgetSize(context, cellSize[1], spanX, spanY, borderSpacing[1]);
- ArrayList<PointF> sizes = new ArrayList<>(2);
+ ArrayList<SizeF> sizes = new ArrayList<>(2);
sizes.add(landSize);
sizes.add(portSize);
return sizes;
@@ -430,17 +411,18 @@
* the right (resp. bottom) for the max. The returned rectangle is set with 0s if the list is
* empty.
*/
- public static Rect getMinMaxSizes(List<PointF> sizes, @Nullable Rect outRect) {
+ public static Rect getMinMaxSizes(List<SizeF> sizes, @Nullable Rect outRect) {
if (outRect == null) {
outRect = new Rect();
}
if (sizes.isEmpty()) {
outRect.set(0, 0, 0, 0);
} else {
- PointF first = sizes.get(0);
- outRect.set((int) first.x, (int) first.y, (int) first.x, (int) first.y);
+ SizeF first = sizes.get(0);
+ outRect.set((int) first.getWidth(), (int) first.getHeight(), (int) first.getWidth(),
+ (int) first.getHeight());
for (int i = 1; i < sizes.size(); i++) {
- outRect.union((int) sizes.get(i).x, (int) sizes.get(i).y);
+ outRect.union((int) sizes.get(i).getWidth(), (int) sizes.get(i).getHeight());
}
}
return outRect;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7beea74..f2dd60e 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -641,7 +641,8 @@
padding.right = hotseatBarSizePx;
}
} else {
- int paddingBottom = hotseatBarSizePx + workspacePageIndicatorHeight
+ int hotseatTop = isTaskbarPresent ? taskbarSize : hotseatBarSizePx;
+ int paddingBottom = hotseatTop + workspacePageIndicatorHeight
+ workspaceBottomPadding - mWorkspacePageIndicatorOverlapWorkspace;
if (isTablet) {
// Pad the left and right of the workspace to ensure consistent spacing
@@ -651,9 +652,10 @@
((inv.numColumns - 1) * cellWidthPx)));
availablePaddingX = (int) Math.min(availablePaddingX,
widthPx * MAX_HORIZONTAL_PADDING_PERCENT);
+ int hotseatVerticalPadding = isTaskbarPresent ? 0
+ : hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx;
int availablePaddingY = Math.max(0, heightPx - edgeMarginPx - paddingBottom
- - (2 * inv.numRows * cellHeightPx) - hotseatBarTopPaddingPx
- - hotseatBarBottomPaddingPx);
+ - (2 * inv.numRows * cellHeightPx) - hotseatVerticalPadding);
padding.set(availablePaddingX / 2, edgeMarginPx + availablePaddingY / 2,
availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
} else {
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 4f4f2a7..b2112ad 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -21,6 +21,7 @@
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
+import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -98,14 +99,20 @@
} else {
lp.gravity = Gravity.BOTTOM;
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
- lp.height = grid.hotseatBarSizePx + insets.bottom;
+ lp.height = grid.isTaskbarPresent
+ ? grid.taskbarSize
+ : grid.hotseatBarSizePx + insets.bottom;
}
- Rect padding = grid.getHotseatLayoutPadding();
- int paddingBottom = padding.bottom;
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && !grid.isVerticalBarLayout()) {
- paddingBottom -= grid.hotseatBarBottomPaddingPx;
+ if (!grid.isTaskbarPresent) {
+ // When taskbar is present, we set the padding separately to ensure a seamless visual
+ // handoff between taskbar and hotseat during drag and drop.
+ Rect padding = grid.getHotseatLayoutPadding();
+ int paddingBottom = padding.bottom;
+ if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && !grid.isVerticalBarLayout()) {
+ paddingBottom -= grid.hotseatBarBottomPaddingPx;
+ }
+ setPadding(padding.left, padding.top, padding.right, paddingBottom);
}
- setPadding(padding.left, padding.top, padding.right, paddingBottom);
setLayoutParams(lp);
InsettableFrameLayout.dispatchInsets(this, insets);
@@ -160,4 +167,11 @@
protected void showInlineQsb() {
//Does nothing
}
+
+ /**
+ * Returns the first View for which the given itemOperator returns true, or null.
+ */
+ public View getFirstItemMatch(Workspace.ItemOperator itemOperator) {
+ return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator);
+ }
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 253a7c7..fa63885 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -121,6 +121,7 @@
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.FolderGridOrganizer;
import com.android.launcher3.folder.FolderIcon;
@@ -2863,6 +2864,10 @@
return false;
}
+ public DragOptions getDefaultWorkspaceDragOptions() {
+ return new DragOptions();
+ }
+
private static class NonConfigInstance {
public Configuration config;
public Bitmap snapshot;
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 781f171..21c40ef 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -59,6 +59,7 @@
public static final int OVERVIEW_ACTIONS = 1 << 6;
public static final int TASKBAR = 1 << 7;
public static final int CLEAR_ALL_BUTTON = 1 << 8;
+ public static final int WORKSPACE_PAGE_INDICATOR = 1 << 9;
/** Mask of all the items that are contained in the apps view. */
public static final int APPS_VIEW_ITEM_MASK =
@@ -188,15 +189,26 @@
}
public int getVisibleElements(Launcher launcher) {
- int flags = HOTSEAT_ICONS | VERTICAL_SWIPE_INDICATOR | TASKBAR;
- if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()
- && !launcher.getDeviceProfile().isVerticalBarLayout()) {
+ DeviceProfile deviceProfile = launcher.getDeviceProfile();
+ int flags = WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR;
+ if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get() && !deviceProfile.isVerticalBarLayout()) {
flags |= HOTSEAT_SEARCH_BOX;
}
+ if (!deviceProfile.isTaskbarPresent) {
+ flags |= HOTSEAT_ICONS;
+ }
return flags;
}
/**
+ * A shorthand for checking getVisibleElements() & elements == elements.
+ * @return Whether all of the given elements are visible.
+ */
+ public boolean areElementsVisible(Launcher launcher, int elements) {
+ return (getVisibleElements(launcher) & elements) == elements;
+ }
+
+ /**
* Fraction shift in the vertical translation UI and related properties
*
* @see com.android.launcher3.allapps.AllAppsTransitionController
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 981ead9..87fb6fb 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -446,6 +446,19 @@
}
updateChildrenLayersEnabled();
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
+ stateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == NORMAL) {
+ if (!mDeferRemoveExtraEmptyScreen) {
+ removeExtraEmptyScreen(true /* stripEmptyScreens */);
+ }
+ stateManager.removeStateListener(this);
+ }
+ }
+ });
+
mDragInfo = null;
mOutlineProvider = null;
mDragSourceInternal = null;
@@ -1877,19 +1890,6 @@
};
}
}
- StateManager<LauncherState> stateManager = mLauncher.getStateManager();
- stateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- if (finalState == NORMAL) {
- if (!mDeferRemoveExtraEmptyScreen) {
- removeExtraEmptyScreen(true /* stripEmptyScreens */);
- }
- stateManager.removeStateListener(this);
- }
- }
- });
-
mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId,
lp.cellX, lp.cellY, item.spanX, item.spanY);
} else {
@@ -2973,7 +2973,7 @@
* @param operators List of operators, in order starting from best matching operator.
* @return
*/
- private View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator... operators) {
+ View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator... operators) {
// This array is filled with the first match for each operator.
final View[] matches = new View[operators.length];
// For efficiency, the outer loop should be CellLayout.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 0e0ddfb..660eeab 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -28,11 +28,13 @@
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.WORKSPACE_PAGE_INDICATOR;
import static com.android.launcher3.anim.Interpolators.LINEAR;
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;
@@ -141,9 +143,11 @@
}
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
- propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
+ propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha,
+ config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
+ float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
- hotseatIconsAlpha, fadeInterpolator);
+ workspacePageIndicatorAlpha, fadeInterpolator);
}
if (config.onlyPlayAtomicComponent()) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a92e1aa..edd9a9f 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -199,7 +199,9 @@
break;
}
}
- rebindAdapters(hasWorkApps);
+ if (!mAH[AdapterHolder.MAIN].appsList.hasFilter()) {
+ rebindAdapters(hasWorkApps);
+ }
if (hasWorkApps) {
resetWorkProfile();
}
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index 9328a3d..f4d735e 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -48,7 +48,6 @@
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
List<AllAppsGridAdapter.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
- boolean drawFallbackFocusedView = true;
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
@@ -60,28 +59,12 @@
decorationHandler.extendBounds(view);
if (sectionInfo.isFocusedView()) {
decorationHandler.onFocusDraw(c, view);
- drawFallbackFocusedView = false;
} else {
decorationHandler.onGroupDraw(c);
}
}
}
}
- // fallback logic in case none of the SearchTarget is labeled as focused item
- if (drawFallbackFocusedView) {
- for (int i = 0; i < parent.getChildCount(); i++) {
- View view = parent.getChildAt(i);
- int position = parent.getChildAdapterPosition(view);
- AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position);
- if (adapterItem.sectionDecorationInfo != null) {
- SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo;
- SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler();
- if (decorationHandler != null) {
- drawDecoration(c, decorationHandler, parent);
- }
- }
- }
- }
}
// Fallback logic in case non of the SearchTarget is labeled as focused item.
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 8016b2d..6b9ed09 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -16,9 +16,6 @@
package com.android.launcher3.anim;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
-
-import android.content.Context;
import android.graphics.Path;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
@@ -67,9 +64,6 @@
*/
public static final Interpolator FINAL_FRAME = t -> t < 1 ? 0 : 1;
- private static final int MIN_SETTLE_DURATION = 200;
- private static final float OVERSHOOT_FACTOR = 0.9f;
-
static {
Path exaggeratedEase = new Path();
exaggeratedEase.moveTo(0, 0);
@@ -175,76 +169,4 @@
float upperBound) {
return t -> Utilities.mapRange(interpolator.getInterpolation(t), lowerBound, upperBound);
}
-
- /**
- * Computes parameters necessary for an overshoot effect.
- */
- public static class OvershootParams {
- public Interpolator interpolator;
- public float start;
- public float end;
- public long duration;
-
- /**
- * Given the input params, sets OvershootParams variables to be used by the caller.
- * @param startProgress The progress from 0 to 1 that the overshoot starts from.
- * @param overshootPastProgress The progress from 0 to 1 where we overshoot past (should
- * either be equal to startProgress or endProgress, depending on if we want to
- * overshoot immediately or only once we reach the end).
- * @param endProgress The final progress from 0 to 1 that we will settle to.
- * @param velocityPxPerMs The initial velocity that causes this overshoot.
- * @param totalDistancePx The distance against which progress is calculated.
- */
- public OvershootParams(float startProgress, float overshootPastProgress,
- float endProgress, float velocityPxPerMs, int totalDistancePx, Context context) {
- velocityPxPerMs = Math.abs(velocityPxPerMs);
- overshootPastProgress = Math.max(overshootPastProgress, startProgress);
- start = startProgress;
- int startPx = (int) (start * totalDistancePx);
- // Overshoot by about half a frame.
- float overshootBy = OVERSHOOT_FACTOR * velocityPxPerMs *
- getSingleFrameMs(context) / totalDistancePx / 2;
- overshootBy = Utilities.boundToRange(overshootBy, 0.02f, 0.15f);
- end = overshootPastProgress + overshootBy;
- int endPx = (int) (end * totalDistancePx);
- int overshootDistance = endPx - startPx;
- // Calculate deceleration necessary to reach overshoot distance.
- // Formula: velocityFinal^2 = velocityInitial^2 + 2 * acceleration * distance
- // 0 = v^2 + 2ad (velocityFinal == 0)
- // a = v^2 / -2d
- float decelerationPxPerMs = velocityPxPerMs * velocityPxPerMs / (2 * overshootDistance);
- // Calculate time necessary to reach peak of overshoot.
- // Formula: acceleration = velocity / time
- // time = velocity / acceleration
- duration = (long) (velocityPxPerMs / decelerationPxPerMs);
-
- // Now that we're at the top of the overshoot, need to settle back to endProgress.
- float settleDistance = end - endProgress;
- int settleDistancePx = (int) (settleDistance * totalDistancePx);
- // Calculate time necessary for the settle.
- // Formula: distance = velocityInitial * time + 1/2 * acceleration * time^2
- // d = 1/2at^2 (velocityInitial = 0, since we just stopped at the top)
- // t = sqrt(2d/a)
- // Above formula assumes constant acceleration. Since we use ACCEL_DEACCEL, we actually
- // have acceleration to halfway then deceleration the rest. So the formula becomes:
- // t = sqrt(d/a) * 2 (half the distance for accel, half for deaccel)
- long settleDuration = (long) Math.sqrt(settleDistancePx / decelerationPxPerMs) * 4;
-
- settleDuration = Math.max(MIN_SETTLE_DURATION, settleDuration);
- // How much of the animation to devote to playing the overshoot (the rest is for settle).
- float overshootFraction = (float) duration / (duration + settleDuration);
- duration += settleDuration;
- // Finally, create the interpolator, composed of two interpolators: an overshoot, which
- // reaches end > 1, and then a settle to endProgress.
- Interpolator overshoot = Interpolators.clampToProgress(DEACCEL, 0, overshootFraction);
- // The settle starts at 1, where 1 is the top of the overshoot, and maps to a fraction
- // such that final progress is endProgress. For example, if we overshot to 1.1 but want
- // to end at 1, we need to map to 1/1.1.
- Interpolator settle = Interpolators.clampToProgress(Interpolators.mapToProgress(
- ACCEL_DEACCEL, 1, (endProgress - start) / (end - start)), overshootFraction, 1);
- interpolator = t -> t <= overshootFraction
- ? overshoot.getInterpolation(t)
- : settle.getInterpolation(t);
- }
- }
}
diff --git a/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
index fa062f5..826ddb0 100644
--- a/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
+++ b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
@@ -2,6 +2,7 @@
import static com.android.launcher3.Utilities.ATLEAST_S;
+import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -25,6 +26,8 @@
private RemoteViews mPreview;
+ private AppWidgetHostView mPreviewAppWidgetHostView;
+
public LivePreviewWidgetCell(Context context) {
this(context, null);
}
@@ -46,8 +49,11 @@
}
/** Resets any resource. This should be called before recycling this view. */
- public void reset() {
+ @Override
+ public void clear() {
+ super.clear();
mPreview = null;
+ mPreviewAppWidgetHostView = null;
}
@Override
@@ -60,6 +66,15 @@
return;
}
}
+
+ if (mPreviewAppWidgetHostView != null) {
+ Bitmap preview = generateFromView(mActivity, mPreviewAppWidgetHostView,
+ mItem.widgetInfo, mPreviewWidth, new int[1]);
+ if (preview != null) {
+ applyPreview(preview);
+ return;
+ }
+ }
super.ensurePreview();
}
@@ -69,8 +84,19 @@
&& mPreview == null
&& item.widgetInfo != null
&& item.widgetInfo.previewLayout != Resources.ID_NULL) {
- mPreview = new RemoteViews(item.widgetInfo.provider.getPackageName(),
- item.widgetInfo.previewLayout);
+ mPreviewAppWidgetHostView = new AppWidgetHostView(getContext());
+ LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
+ LauncherAppWidgetProviderInfo.fromProviderInfo(getContext(),
+ item.widgetInfo.clone());
+ // A hack to force the initial layout to be the preview layout since there is no API for
+ // rendering a preview layout for work profile apps yet. For non-work profile layout, a
+ // proper solution is to use RemoteViews(PackageName, LayoutId).
+ launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;
+ mPreviewAppWidgetHostView.setAppWidget(/* appWidgetId= */ -1,
+ launcherAppWidgetProviderInfo);
+ mPreviewAppWidgetHostView.setPadding(/* left= */ 0, /* top= */0, /* right= */
+ 0, /* bottom= */ 0);
+ mPreviewAppWidgetHostView.updateAppWidget(/* remoteViews= */ null);
}
super.applyFromCellItem(item, loader);
@@ -84,23 +110,27 @@
*/
public static Bitmap generateFromRemoteViews(BaseActivity activity, RemoteViews views,
LauncherAppWidgetProviderInfo info, int previewSize, int[] preScaledWidthOut) {
+ try {
+ return generateFromView(activity, views.apply(activity, new FrameLayout(activity)),
+ info, previewSize, preScaledWidthOut);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static Bitmap generateFromView(BaseActivity activity, View v,
+ LauncherAppWidgetProviderInfo info, int previewSize, int[] preScaledWidthOut) {
DeviceProfile dp = activity.getDeviceProfile();
int viewWidth = dp.cellWidthPx * info.spanX;
int viewHeight = dp.cellHeightPx * info.spanY;
- final View v;
- try {
- v = views.apply(activity, new FrameLayout(activity));
- v.measure(MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY));
+ v.measure(MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY));
- viewWidth = v.getMeasuredWidth();
- viewHeight = v.getMeasuredHeight();
- v.layout(0, 0, viewWidth, viewHeight);
- } catch (Exception e) {
- return null;
- }
+ viewWidth = v.getMeasuredWidth();
+ viewHeight = v.getMeasuredHeight();
+ v.layout(0, 0, viewWidth, viewHeight);
preScaledWidthOut[0] = viewWidth;
final int bitmapWidth, bitmapHeight;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 209c5be..f6c7c06 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -192,6 +192,16 @@
loadWorkspace(allShortcuts);
logger.addSplit("loadWorkspace");
+ // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
+ // sanitizeData should not be invoked if the workspace is loaded from a db different
+ // from the main db as defined in the invariant device profile.
+ // (e.g. both grid preview and minimal device mode uses a different db)
+ if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
+ verifyNotStopped();
+ sanitizeData();
+ logger.addSplit("sanitizeData");
+ }
+
verifyNotStopped();
mResults.bindWorkspace();
logger.addSplit("bindWorkspace");
@@ -274,14 +284,6 @@
loadFolderNames();
}
- // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
- // sanitizeData should not be invoked if the workspace is loaded from a db different
- // from the main db as defined in the invariant device profile.
- // (e.g. both grid preview and minimal device mode uses a different db)
- if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
- sanitizeData();
- }
-
verifyNotStopped();
updateHandler.finish();
logger.addSplit("finish icon update");
@@ -875,10 +877,11 @@
mBgDataModel.itemsIdMap.remove(folderId);
}
}
- // Remove any ghost widgets
- LauncherSettings.Settings.call(contentResolver,
- LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
+
}
+ // Remove any ghost widgets
+ LauncherSettings.Settings.call(contentResolver,
+ LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
// Update pinned state of model shortcuts
mBgDataModel.updateShortcutPinnedState(context);
diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
index 434776c..c0dc34a 100644
--- a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.model;
-import android.content.Intent;
import android.os.UserHandle;
import com.android.launcher3.LauncherAppState;
@@ -66,8 +65,7 @@
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
synchronized (dataModel) {
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
- Intent intent = si.getIntent();
- if ((intent != null) && mPackageName.equals(intent.getPackage())) {
+ if (mPackageName.equals(si.getTargetPackage())) {
si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
si.setProgressLevel(downloadInfo);
updatedWorkspaceItems.add(si);
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 1380e9e..9889a80 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.model;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -72,9 +71,8 @@
synchronized (dataModel) {
final HashSet<ItemInfo> updates = new HashSet<>();
dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
- Intent intent = si.getIntent();
- if (si.hasPromiseIconUi() && (intent != null)
- && mInstallInfo.packageName.equals(intent.getPackage())) {
+ if (si.hasPromiseIconUi()
+ && mInstallInfo.packageName.equals(si.getTargetPackage())) {
int installProgress = mInstallInfo.progress;
si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING);
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 00ac12f..e54f1e7 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -184,6 +184,24 @@
return Optional.ofNullable(getIntent()).map(Intent::getComponent).orElse(mComponentName);
}
+ /**
+ * Returns this item's package name.
+ *
+ * Prioritizes the component package name, then uses the intent package name as a fallback.
+ * This ensures deep shortcuts are supported.
+ */
+ @Nullable
+ public String getTargetPackage() {
+ ComponentName component = getTargetComponent();
+ Intent intent = getIntent();
+
+ return component != null
+ ? component.getPackageName()
+ : intent != null
+ ? intent.getPackage()
+ : null;
+ }
+
public void writeToValues(ContentWriter writer) {
writer.put(LauncherSettings.Favorites.ITEM_TYPE, itemType)
.put(LauncherSettings.Favorites.CONTAINER, container)
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 408796f..6189dc9 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -268,7 +268,9 @@
} else {
lp.leftMargin = lp.rightMargin = 0;
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
+ lp.bottomMargin = grid.isTaskbarPresent
+ ? grid.workspacePadding.bottom + insets.bottom
+ : grid.hotseatBarSizePx + insets.bottom;
}
setLayoutParams(lp);
}
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index 459aefe..a191df4 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -32,11 +32,11 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.provider.Settings;
import android.util.AttributeSet;
+import android.util.SizeF;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -299,7 +299,7 @@
InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
Bundle opts = new Bundle();
- ArrayList<PointF> sizes = AppWidgetResizeFrame
+ ArrayList<SizeF> sizes = AppWidgetResizeFrame
.getWidgetSizes(getContext(), idp.numColumns, 1);
Rect size = AppWidgetResizeFrame.getMinMaxSizes(sizes, null /* outRect */);
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index beb5b68..a18f340 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -302,10 +302,6 @@
}
private PendingAnimation createAnimationToNewWorkspaceInternal(final STATE_TYPE state) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "createAnimationToNewWorkspaceInternal: "
- + state);
- }
PendingAnimation builder = new PendingAnimation(mConfig.duration);
if (mConfig.getAnimComponents() != 0) {
for (StateHandler handler : getStateHandlers()) {
@@ -328,9 +324,6 @@
@Override
public void onAnimationSuccess(Animator animator) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "onAnimationSuccess: " + state);
- }
onStateTransitionEnd(state);
}
};
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 44bcc34..fce8fff 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -93,6 +93,6 @@
@Override
public int getVisibleElements(Launcher launcher) {
- return super.getVisibleElements(launcher) & ~TASKBAR;
+ return (super.getVisibleElements(launcher) | HOTSEAT_ICONS) & ~TASKBAR;
}
}
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index ec949eb..e4c67ee 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -75,6 +75,7 @@
ANIM_DEPTH,
ANIM_OVERVIEW_ACTIONS_FADE,
ANIM_TASKBAR_FADE,
+ ANIM_HOTSEAT_FADE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimType {}
@@ -95,8 +96,9 @@
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 = 17;
+ private static final int ANIM_TYPES_COUNT = 18;
protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 72bbc43..7cb6e34 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -103,8 +103,8 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
- public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
public static final String NO_SWIPE_TO_HOME = "b/158017601";
public static final String WORK_PROFILE_REMOVED = "b/159671700";
public static final String TIS_NO_EVENTS = "b/180915942";
+ public static final String GET_RECENTS_FAILED = "b/177472267";
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index b28d6f7..6f1b2f9 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -202,10 +202,6 @@
mFromState = newFromState;
mToState = newToState;
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "reinitCurrentAnimation: "
- + newToState.ordinal + " " + getClass().getSimpleName());
- }
mStartProgress = 0;
mPassedOverviewAtomicThreshold = false;
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 919673f..f876dd9 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -57,7 +57,7 @@
if (!(v.getTag() instanceof ItemInfo)) return false;
launcher.setWaitingForResult(null);
- beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions());
+ beginDrag(v, launcher, (ItemInfo) v.getTag(), launcher.getDefaultWorkspaceDragOptions());
return true;
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 54e51b2..3285c18 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,12 +16,9 @@
package com.android.launcher3.widget;
-import static com.android.launcher3.Utilities.ATLEAST_S;
-
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.PointF;
import android.os.Handler;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
@@ -219,16 +216,6 @@
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
-
- if (ATLEAST_S) {
- float density = getContext().getResources().getDisplayMetrics().density;
- setCurrentSize(new PointF(w / density, h / density));
- }
- }
-
- @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(getClass().getName());
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 8c3206d..4b113d8 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -30,6 +29,7 @@
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
+import android.util.SizeF;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.View;
@@ -112,7 +112,7 @@
}
@Override
- public void updateAppWidgetSize(Bundle newOptions, List<PointF> sizes) {
+ public void updateAppWidgetSize(Bundle newOptions, List<SizeF> sizes) {
// No-op
}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 8c315fd..ea6f0c3 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -61,8 +61,8 @@
/** Widget preview width is calculated by multiplying this factor to the widget cell width. */
private static final float PREVIEW_SCALE = 0.8f;
- private int mPreviewWidth;
- private int mPreviewHeight;
+ protected int mPreviewWidth;
+ protected int mPreviewHeight;
protected int mPresetPreviewSize;
private int mCellSize;
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index 31cbff6..12e0d43 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -3,11 +3,11 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.content.Context;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
+import android.util.SizeF;
import android.view.View;
import com.android.launcher3.AppWidgetResizeFrame;
@@ -19,6 +19,7 @@
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
+import java.util.stream.Collectors;
public class WidgetHostViewLoader implements DragController.DragListener {
private static final String TAG = "WidgetHostViewLoader";
@@ -154,7 +155,7 @@
}
public static Bundle getDefaultOptionsForWidget(Context context, PendingAddWidgetInfo info) {
- ArrayList<PointF> sizes = AppWidgetResizeFrame
+ ArrayList<SizeF> sizes = AppWidgetResizeFrame
.getWidgetSizes(context, info.spanX, info.spanY);
Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context,
@@ -163,19 +164,19 @@
float xPaddingDips = (padding.left + padding.right) / density;
float yPaddingDips = (padding.top + padding.bottom) / density;
- for (PointF size : sizes) {
- size.x = Math.max(0.f, size.x - xPaddingDips);
- size.y = Math.max(0.f, size.y - yPaddingDips);
- }
+ ArrayList<SizeF> paddedSizes = sizes.stream().map(
+ size -> new SizeF(Math.max(0.f, size.getWidth() - xPaddingDips),
+ Math.max(0.f, size.getHeight() - yPaddingDips))).collect(
+ Collectors.toCollection(ArrayList::new));
- Rect rect = AppWidgetResizeFrame.getMinMaxSizes(sizes, null /* outRect */);
+ Rect rect = AppWidgetResizeFrame.getMinMaxSizes(paddedSizes, null /* outRect */);
Bundle options = new Bundle();
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, rect.left);
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, rect.top);
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, rect.right);
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, rect.bottom);
- options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, sizes);
+ options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, paddedSizes);
return options;
}
}
diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
index a5ed20a..95fa05f 100644
--- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
+++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
@@ -16,10 +16,10 @@
package com.android.launcher3.widget.picker;
import android.view.View;
+import android.view.ViewGroup.MarginLayoutParams;
import android.widget.RelativeLayout;
import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.widget.picker.WidgetsFullSheet.SearchAndRecommendationViewHolder;
@@ -33,20 +33,21 @@
RecyclerViewFastScroller.OnFastScrollChangeListener {
private final boolean mHasWorkProfile;
private final SearchAndRecommendationViewHolder mViewHolder;
- private final RecyclerView mPrimaryRecyclerView;
+ private final WidgetsRecyclerView mPrimaryRecyclerView;
// The following are only non null if mHasWorkProfile is true.
- @Nullable private final RecyclerView mWorkRecyclerView;
+ @Nullable private final WidgetsRecyclerView mWorkRecyclerView;
@Nullable private final View mPrimaryWorkTabsView;
@Nullable private final PersonalWorkPagedView mPrimaryWorkViewPager;
+ private WidgetsRecyclerView mCurrentRecyclerView;
private int mMaxCollapsibleHeight = 0;
SearchAndRecommendationsScrollController(
boolean hasWorkProfile,
SearchAndRecommendationViewHolder viewHolder,
- RecyclerView primaryRecyclerView,
- @Nullable RecyclerView workRecyclerView,
+ WidgetsRecyclerView primaryRecyclerView,
+ @Nullable WidgetsRecyclerView workRecyclerView,
@Nullable View personalWorkTabsView,
@Nullable PersonalWorkPagedView primaryWorkViewPager) {
mHasWorkProfile = hasWorkProfile;
@@ -55,6 +56,12 @@
mWorkRecyclerView = workRecyclerView;
mPrimaryWorkTabsView = personalWorkTabsView;
mPrimaryWorkViewPager = primaryWorkViewPager;
+ mCurrentRecyclerView = mPrimaryRecyclerView;
+ }
+
+ /** Sets the current active {@link WidgetsRecyclerView}. */
+ public void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView) {
+ mCurrentRecyclerView = currentRecyclerView;
}
/**
@@ -64,10 +71,10 @@
// The maximum vertical distance, in pixels, until the last collapsible element is not
// visible from the screen when the user scrolls down the recycler view.
mMaxCollapsibleHeight = mViewHolder.mContainer.getPaddingTop()
- + mViewHolder.mCollapseHandle.getMeasuredHeight()
- + mViewHolder.mHeaderTitle.getMeasuredHeight();
+ + measureHeightWithVerticalMargins(mViewHolder.mCollapseHandle)
+ + measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle);
- int topContainerHeight = mViewHolder.mContainer.getMeasuredHeight();
+ int topContainerHeight = measureHeightWithVerticalMargins(mViewHolder.mContainer);
if (mHasWorkProfile) {
// In a work profile setup, the full widget sheet contains the following views:
// ------- -|
@@ -114,8 +121,8 @@
//
// When the views are first inflated, the sum of topOffsetAfterAllViewsCollapsed and
// mMaxCollapsibleDistance should equal to the top container height.
- int tabsViewActualHeight =
- mPrimaryWorkTabsView.getMeasuredHeight() - mPrimaryWorkTabsView.getPaddingTop();
+ int tabsViewActualHeight = measureHeightWithVerticalMargins(mPrimaryWorkTabsView)
+ - mPrimaryWorkTabsView.getPaddingTop();
int topOffsetAfterAllViewsCollapsed =
topContainerHeight + tabsViewActualHeight - mMaxCollapsibleHeight;
@@ -149,9 +156,12 @@
* views (e.g. recycler views, tabs) upon scrolling.
*/
@Override
- public void onThumbOffsetYChanged(int y) {
+ public void onThumbOffsetYChanged(int unused) {
+ // Always use the recycler view offset because fast scroller offset has a different scale.
+ int recyclerViewYOffset = mCurrentRecyclerView.getCurrentScrollY();
+ if (recyclerViewYOffset < 0) return;
if (mMaxCollapsibleHeight > 0) {
- int yDisplacement = Math.max(-y, -mMaxCollapsibleHeight);
+ int yDisplacement = Math.max(-recyclerViewYOffset, -mMaxCollapsibleHeight);
mViewHolder.mHeaderTitle.setTranslationY(yDisplacement);
mViewHolder.mSearchBar.setTranslationY(yDisplacement);
if (mHasWorkProfile) {
@@ -159,4 +169,20 @@
}
}
}
+
+ /** Resets any previous view translation. */
+ public void reset() {
+ mViewHolder.mHeaderTitle.setTranslationY(0);
+ mViewHolder.mSearchBar.setTranslationY(0);
+ if (mHasWorkProfile) {
+ mPrimaryWorkTabsView.setTranslationY(0);
+ }
+ }
+
+ /** private the height, in pixel, + the vertical margins of a given view. */
+ private static int measureHeightWithVerticalMargins(View view) {
+ MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();
+ return view.getMeasuredHeight() + marginLayoutParams.bottomMargin
+ + marginLayoutParams.topMargin;
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 91b79f9..52a2fc5 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -149,7 +149,10 @@
@Override
public void onActivePageChanged(int currentActivePage) {
- mAdapters.get(currentActivePage).mWidgetsRecyclerView.bindFastScrollbar();
+ WidgetsRecyclerView currentRecyclerView =
+ mAdapters.get(currentActivePage).mWidgetsRecyclerView;
+ currentRecyclerView.bindFastScrollbar();
+ mSearchAndRecommendationsScrollController.setCurrentRecyclerView(currentRecyclerView);
reset();
}
@@ -159,6 +162,7 @@
if (mHasWorkProfile) {
mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView.scrollToTop();
}
+ mSearchAndRecommendationsScrollController.reset();
}
@VisibleForTesting
@@ -241,6 +245,12 @@
mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
maxSpansPerRow);
}
+
+ if (mInitialTabsHeight == 0 && mTabsView != null) {
+ mInitialTabsHeight = measureHeightWithVerticalMargins(mTabsView);
+ }
+
+ mSearchAndRecommendationsScrollController.updateMarginAndPadding();
}
@Override
@@ -255,12 +265,6 @@
contentLeft + contentWidth, height);
setTranslationShift(mTranslationShift);
-
- if (mInitialTabsHeight == 0 && mTabsView != null) {
- mInitialTabsHeight = mTabsView.getMeasuredHeight();
- }
-
- mSearchAndRecommendationsScrollController.updateMarginAndPadding();
}
@Override
@@ -371,7 +375,14 @@
// No need to check work profile here because mInitialTabHeight is always 0 if there is no
// work profile.
return mInitialTabsHeight
- + mSearchAndRecommendationViewHolder.mContainer.getMeasuredHeight();
+ + measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mContainer);
+ }
+
+ /** private the height, in pixel, + the vertical margins of a given view. */
+ private static int measureHeightWithVerticalMargins(View view) {
+ MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();
+ return view.getMeasuredHeight() + marginLayoutParams.bottomMargin
+ + marginLayoutParams.topMargin;
}
/** A holder class for holding adapters & their corresponding recycler view. */
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 823fb7b..070a9aa 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -157,14 +157,29 @@
private void setTitles(WidgetsListHeaderEntry entry) {
mTitle.setText(entry.mPkgItem.title);
- if (entry.widgetsCount > 0) {
- Resources resources = getContext().getResources();
- mSubtitle.setText(resources.getQuantityString(R.plurals.widgets_tray_subtitle,
- entry.widgetsCount, entry.widgetsCount));
- mSubtitle.setVisibility(VISIBLE);
- } else {
+ Resources resources = getContext().getResources();
+ if (entry.widgetsCount == 0 && entry.shortcutsCount == 0) {
mSubtitle.setVisibility(GONE);
+ return;
}
+
+ String subtitle;
+ if (entry.widgetsCount > 0 && entry.shortcutsCount > 0) {
+ String widgetsCount = resources.getQuantityString(R.plurals.widgets_count,
+ entry.widgetsCount, entry.widgetsCount);
+ String shortcutsCount = resources.getQuantityString(R.plurals.shortcuts_count,
+ entry.shortcutsCount, entry.shortcutsCount);
+ subtitle = resources.getString(R.string.widgets_and_shortcuts_count, widgetsCount,
+ shortcutsCount);
+ } else if (entry.widgetsCount > 0) {
+ subtitle = resources.getQuantityString(R.plurals.widgets_count,
+ entry.widgetsCount, entry.widgetsCount);
+ } else {
+ subtitle = resources.getQuantityString(R.plurals.shortcuts_count,
+ entry.shortcutsCount, entry.shortcutsCount);
+ }
+ mSubtitle.setText(subtitle);
+ mSubtitle.setVisibility(VISIBLE);
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 9c8684a..28ffd54 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -153,7 +153,7 @@
} else {
for (int j = tableRow.getChildCount(); j < widgetItems.size(); j++) {
WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
- R.layout.widget_cell, tableRow, false);
+ R.layout.live_preview_widget_cell, tableRow, false);
// set up touch.
widget.setOnClickListener(mIconClickListener);
widget.setOnLongClickListener(mIconLongClickListener);
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java b/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
new file mode 100644
index 0000000..d12782c
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * An interface for a pipeline to handle widgets search.
+ */
+public interface WidgetsPickerSearchPipeline {
+
+ /**
+ * Performs a search query asynchronically. Invokes {@code callback} when the search is
+ * complete.
+ */
+ void query(String input, Consumer<List<WidgetsListBaseEntry>> callback);
+
+ /**
+ * Cancels any ongoing search request.
+ */
+ default void cancel() {};
+
+ /**
+ * Cleans up after search is no longer needed.
+ */
+ default void destroy() {};
+}
diff --git a/src_build_config/BuildConfig.java b/src_build_config/com/android/launcher3/BuildConfig.java
similarity index 100%
rename from src_build_config/BuildConfig.java
rename to src_build_config/com/android/launcher3/BuildConfig.java
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 5e41d43d..63220ad 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -77,6 +78,17 @@
mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
}
+ @After
+ public void resumeAppStoreUpdate() {
+ executeOnLauncher(launcher -> {
+ if (launcher == null || launcher.getAppsView() == null) {
+ return;
+ }
+ launcher.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED, "resuming AppStore updates");
+ });
+ }
+
@Test
public void workTabExists() {
mDevice.pressHome();
@@ -145,6 +157,12 @@
"work profile status (" + mProfileUserId + ") :"
+ launcher.getAppsView().isWorkTabVisible()));
+
+ executeOnLauncher(launcher -> {
+ launcher.getAppsView().getAppsStore().enableDeferUpdates(DEFER_UPDATES_TEST);
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Defer all apps update");
+ });
+
AtomicInteger attempt = new AtomicInteger(0);
// verify work edu is seen next
waitForLauncherCondition("Launcher did not show the next edu screen", l -> {
@@ -157,7 +175,6 @@
if (((AllAppsPagedView) l.getAppsView().getContentView()).getCurrentPage()
!= WORK_PAGE) {
Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Work page not highlighted");
- return false;
}
return ((TextView) workEduView.findViewById(R.id.content_text)).getText().equals(
l.getResources().getString(R.string.work_profile_edu_work_apps));