Merge "Only inset widgets if workspaceTopPadding is greater than the widget padding." into sc-dev
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 754782b..65cdcf0 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -53,14 +53,17 @@
public static final int ERROR_PERMISSIONS = 1;
private static final String TAG = "TaskOverlayFactoryGo";
- // Empty constructor required for ResourceBasedOverride
- public TaskOverlayFactoryGo(Context context) {}
+ private AssistContentRequester mContentRequester;
+
+ public TaskOverlayFactoryGo(Context context) {
+ mContentRequester = new AssistContentRequester(context);
+ }
/**
* Create a new overlay instance for the given View
*/
public TaskOverlayGo createOverlay(TaskThumbnailView thumbnailView) {
- return new TaskOverlayGo(thumbnailView);
+ return new TaskOverlayGo(thumbnailView, mContentRequester);
}
/**
@@ -72,9 +75,12 @@
private String mTaskPackageName;
private String mWebUrl;
private boolean mAssistPermissionsEnabled;
+ private AssistContentRequester mFactoryContentRequester;
- private TaskOverlayGo(TaskThumbnailView taskThumbnailView) {
+ private TaskOverlayGo(TaskThumbnailView taskThumbnailView,
+ AssistContentRequester assistContentRequester) {
super(taskThumbnailView);
+ mFactoryContentRequester = assistContentRequester;
}
/**
@@ -105,9 +111,7 @@
}
int taskId = task.key.id;
- AssistContentRequester contentRequester =
- new AssistContentRequester(mApplicationContext);
- contentRequester.requestAssistContent(taskId, this::onAssistContentReceived);
+ mFactoryContentRequester.requestAssistContent(taskId, this::onAssistContentReceived);
}
/** Provide Assist Content to the overlay. */
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index 96a94ba..763e45e 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -25,15 +25,15 @@
<TextView
android:id="@+id/task_name"
- android:background="?android:attr/textColorPrimary"
- android:textColor="?android:attr/textColorPrimaryInverse"
+ android:background="?android:attr/colorPrimary"
+ android:textColor="?android:attr/textColorPrimary"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_marginBottom="2dp"
- android:paddingTop="@dimen/task_card_menu_option_vertical_padding"
- android:paddingBottom="@dimen/task_card_menu_option_vertical_padding"
- android:textSize="24sp"/>
+ android:paddingTop="@dimen/task_menu_vertical_padding"
+ android:paddingBottom="@dimen/task_menu_vertical_padding"
+ android:textSize="16sp"/>
<LinearLayout
android:id="@+id/menu_option_layout"
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
index 59c7263..19ca3e3 100644
--- a/quickstep/res/layout/task_view_menu_option.xml
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -21,7 +21,7 @@
android:orientation="vertical"
android:paddingTop="@dimen/task_card_menu_option_vertical_padding"
android:paddingBottom="@dimen/task_card_menu_option_vertical_padding"
- android:background="?android:attr/textColorPrimary"
+ android:background="?android:attr/colorPrimary"
android:theme="@style/PopupItem" >
<View
@@ -30,7 +30,7 @@
android:layout_height="@dimen/system_shortcut_icon_size"
android:layout_marginStart="@dimen/task_menu_option_start_margin"
android:layout_gravity="center_horizontal"
- android:backgroundTint="?android:attr/textColorPrimaryInverse"/>
+ android:backgroundTint="?android:attr/textColorPrimary"/>
<TextView
style="@style/BaseIcon"
@@ -39,7 +39,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/task_menu_option_start_margin"
android:textSize="14sp"
- android:textColor="?android:attr/textColorPrimaryInverse"
+ android:textColor="?android:attr/textColorPrimary"
android:focusable="false" />
</LinearLayout>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index b39a8d3..60eeaff 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -45,8 +45,9 @@
<!-- These speeds are in dp/s -->
<dimen name="max_task_dismiss_drag_velocity">2.25dp</dimen>
- <dimen name="default_task_dismiss_drag_velocity">1.75dp</dimen>
- <dimen name="default_task_dismiss_drag_velocity_grid">0.75dp</dimen>
+ <dimen name="default_task_dismiss_drag_velocity">1.5dp</dimen>
+ <dimen name="default_task_dismiss_drag_velocity_grid">1dp</dimen>
+ <dimen name="default_task_dismiss_drag_velocity_grid_focus_task">5dp</dimen>
<dimen name="recents_page_spacing">16dp</dimen>
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
@@ -74,7 +75,8 @@
<!-- Total space (start + end) between the task card and the edge of the screen
in various configurations -->
- <dimen name="task_card_menu_option_vertical_padding">8dp</dimen>
+ <dimen name="task_card_menu_option_vertical_padding">16dp</dimen>
+ <dimen name="task_menu_vertical_padding">8dp</dimen>
<dimen name="task_card_margin">8dp</dimen>
<dimen name="task_card_menu_shadow_height">3dp</dimen>
<dimen name="task_menu_option_start_margin">12dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 6912f94..36322ce 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -66,7 +66,9 @@
import android.os.SystemProperties;
import android.util.Pair;
import android.util.Size;
+import android.view.SurfaceControl;
import android.view.View;
+import android.view.ViewRootImpl;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -98,6 +100,7 @@
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -921,12 +924,39 @@
BACKGROUND_APP.getDepth(mLauncher))
.setDuration(APP_LAUNCH_DURATION);
if (allowBlurringLauncher) {
- depthController.setSurfaceToApp(RemoteAnimationProvider.findLowestOpaqueLayerTarget(
- appTargets, MODE_OPENING));
+ final SurfaceControl dimLayer;
+ if (BlurUtils.supportsBlursOnWindows()) {
+ // Create a temporary effect layer, that lives on top of launcher, so we can apply
+ // the blur to it. The EffectLayer will be fullscreen, which will help with caching
+ // optimizations on the SurfaceFlinger side:
+ // - Results would be able to be cached as a texture
+ // - There won't be texture allocation overhead, because EffectLayers don't have
+ // buffers
+ ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
+ SurfaceControl parent = viewRootImpl != null
+ ? viewRootImpl.getSurfaceControl()
+ : null;
+ dimLayer = new SurfaceControl.Builder()
+ .setName("Blur layer")
+ .setParent(parent)
+ .setOpaque(false)
+ .setHidden(false)
+ .setEffectLayer()
+ .build();
+ } else {
+ dimLayer = null;
+ }
+
+ depthController.setSurface(dimLayer);
backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- depthController.setSurfaceToApp(null);
+ depthController.setSurface(null);
+ if (dimLayer != null) {
+ new SurfaceControl.Transaction()
+ .remove(dimLayer)
+ .apply();
+ }
}
});
}
@@ -1379,14 +1409,14 @@
: APP_LAUNCH_ALPHA_DOWN_DURATION;
iconAlphaStart = hasSplashScreen && !hasDifferentAppIcon ? 0 : 1f;
- // TOOD: Share value from shell when available.
- final float windowIconSize = Utilities.pxFromSp(108, r.getDisplayMetrics());
+ final int windowIconSize = ResourceUtils.getDimenByName("starting_surface_icon_size",
+ r, 108);
cropCenterXStart = windowTargetBounds.centerX();
cropCenterYStart = windowTargetBounds.centerY();
- cropWidthStart = (int) windowIconSize;
- cropHeightStart = (int) windowIconSize;
+ cropWidthStart = windowIconSize;
+ cropHeightStart = windowIconSize;
cropWidthEnd = windowTargetBounds.width();
cropHeightEnd = windowTargetBounds.height();
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index e608885..46ef698 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -25,7 +25,9 @@
import android.animation.ObjectAnimator;
import android.os.IBinder;
import android.util.FloatProperty;
+import android.view.SurfaceControl;
import android.view.View;
+import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
import com.android.launcher3.BaseActivity;
@@ -37,9 +39,6 @@
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.BlurUtils;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SurfaceControlCompat;
-import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WallpaperManagerCompat;
/**
@@ -91,7 +90,8 @@
@Override
public void onDraw() {
View view = mLauncher.getDragLayer();
- setSurface(new SurfaceControlCompat(view));
+ ViewRootImpl viewRootImpl = view.getViewRootImpl();
+ setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
}
};
@@ -102,7 +102,7 @@
*/
private int mMaxBlurRadius;
private WallpaperManagerCompat mWallpaperManager;
- private SurfaceControlCompat mSurface;
+ private SurfaceControl mSurface;
/**
* Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
* @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
@@ -157,11 +157,7 @@
/**
* Sets the specified app target surface to apply the blur to.
*/
- public void setSurfaceToApp(RemoteAnimationTargetCompat target) {
- setSurface(target == null ? null : target.leash);
- }
-
- private void setSurface(SurfaceControlCompat surface) {
+ public void setSurface(SurfaceControl surface) {
if (mSurface != surface) {
mSurface = surface;
if (surface != null) {
@@ -219,7 +215,7 @@
if (supportsBlur) {
boolean isOpaque = mLauncher.getScrimView().isFullyOpaque();
int blur = isOpaque ? 0 : (int) (mDepth * mMaxBlurRadius);
- new TransactionCompat()
+ new SurfaceControl.Transaction()
.setBackgroundBlurRadius(mSurface, blur)
.setOpaque(mSurface, isOpaque)
.apply();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index c6ea953..180af0b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -21,6 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
@@ -72,6 +73,7 @@
private float mProgressMultiplier;
private float mEndDisplacement;
private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
+ private Float mOverrideVelocity = null;
private TaskView mTaskBeingDragged;
@@ -268,6 +270,7 @@
mCurrentAnimation.pause();
}
mFlingBlockCheck.unblockFling();
+ mOverrideVelocity = null;
}
@Override
@@ -283,19 +286,36 @@
mFlingBlockCheck.onEvent();
}
- // Once halfway through task dismissal interpolation, switch from reversible dragging-task
- // animation to playing the remaining task translation animations
- if (mCurrentAnimation.getProgressFraction() < ANIMATION_PROGRESS_FRACTION_MIDPOINT) {
- // Halve the value as we are animating the drag across the full length for only the
- // first half of the progress
- mCurrentAnimation.setPlayFraction(
- Utilities.boundToRange(totalDisplacement * mProgressMultiplier / 2, 0, 1));
+ if (isGoingUp) {
+ if (mCurrentAnimation.getProgressFraction() < ANIMATION_PROGRESS_FRACTION_MIDPOINT) {
+ // Halve the value when dismissing, as we are animating the drag across the full
+ // length for only the first half of the progress
+ mCurrentAnimation.setPlayFraction(
+ Utilities.boundToRange(totalDisplacement * mProgressMultiplier / 2, 0, 1));
+ } else {
+ // Set mOverrideVelocity to control task dismiss velocity in onDragEnd
+ int velocityDimenId = R.dimen.default_task_dismiss_drag_velocity;
+ if (mRecentsView.showAsGrid()) {
+ if (mTaskBeingDragged.isFocusedTask()) {
+ velocityDimenId =
+ R.dimen.default_task_dismiss_drag_velocity_grid_focus_task;
+ } else {
+ velocityDimenId = R.dimen.default_task_dismiss_drag_velocity_grid;
+ }
+ }
+ mOverrideVelocity = -mTaskBeingDragged.getResources().getDimension(velocityDimenId);
+
+ // Once halfway through task dismissal interpolation, switch from reversible
+ // dragging-task animation to playing the remaining task translation animations
+ final long now = SystemClock.uptimeMillis();
+ MotionEvent upAction = MotionEvent.obtain(now, now,
+ MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+ mDetector.onTouchEvent(upAction);
+ upAction.recycle();
+ }
} else {
- float dragVelocity = -mTaskBeingDragged.getResources().getDimension(
- mRecentsView.showAsGrid() ? R.dimen.default_task_dismiss_drag_velocity_grid
- : R.dimen.default_task_dismiss_drag_velocity);
- onDragEnd(dragVelocity);
- return true;
+ mCurrentAnimation.setPlayFraction(
+ Utilities.boundToRange(totalDisplacement * mProgressMultiplier, 0, 1));
}
return true;
@@ -303,6 +323,10 @@
@Override
public void onDragEnd(float velocity) {
+ if (mOverrideVelocity != null) {
+ velocity = mOverrideVelocity;
+ mOverrideVelocity = null;
+ }
// Limit velocity, as very large scalar values make animations play too quickly
float maxTaskDismissDragVelocity = mTaskBeingDragged.getResources().getDimension(
R.dimen.max_task_dismiss_drag_velocity);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 54c39a7..306032c 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -972,6 +972,10 @@
}
if (endTarget == HOME) {
duration = HOME_DURATION;
+ // Early detach the nav bar once the endTarget is determined as HOME
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.detachNavigationBarFromApp(true);
+ }
} else if (endTarget == RECENTS) {
if (mRecentsView != null) {
int nearestPage = mRecentsView.getDestinationPage();
@@ -1398,6 +1402,10 @@
mLauncherTransitionController.getNormalController().getAnimationPlayer().end();
mLauncherTransitionController = null;
}
+
+ if (mRecentsView != null) {
+ mRecentsView.abortScrollerAnimation();
+ }
}
/**
@@ -1416,7 +1424,7 @@
private void resetStateForAnimationCancel() {
boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
- mActivityInterface.onTransitionCancelled(wasVisible);
+ mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
if (mActivity != null) {
@@ -1492,7 +1500,7 @@
if (LIVE_TILE.get()) {
mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
if (mRecentsAnimationController != null) {
- mRecentsAnimationController.getController().detachNavigationBarFromApp(true);
+ mRecentsAnimationController.detachNavigationBarFromApp(true);
}
} else if (!hasTargets() || mRecentsAnimationController == null) {
// If there are no targets or the animation not started, then there is nothing to finish
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 2696cbe..4ae6fa8 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -86,12 +86,22 @@
mBackgroundState = backgroundState;
}
- public void onTransitionCancelled(boolean activityVisible) {
+ /**
+ * Called when the current gesture transition is cancelled.
+ * @param activityVisible Whether the user can see the changes we make here, so try to animate.
+ * @param endTarget If the gesture ended before we got cancelled, where we were headed.
+ */
+ public void onTransitionCancelled(boolean activityVisible,
+ @Nullable GestureState.GestureEndTarget endTarget) {
ACTIVITY_TYPE activity = getCreatedActivity();
if (activity == null) {
return;
}
STATE_TYPE startState = activity.getStateManager().getRestState();
+ if (endTarget != null) {
+ // We were on our way to this state when we got canceled, end there instead.
+ startState = stateFromGestureEndTarget(endTarget);
+ }
activity.getStateManager().goToState(startState, activityVisible);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 462f714..50d0569 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -155,6 +155,14 @@
}
/**
+ * @see RecentsAnimationControllerCompat#detachNavigationBarFromApp
+ */
+ @UiThread
+ public void detachNavigationBarFromApp(boolean moveHomeToTop) {
+ UI_HELPER_EXECUTOR.execute(() -> mController.detachNavigationBarFromApp(moveHomeToTop));
+ }
+
+ /**
* Sets the final surface transaction on a Task. This is used by Launcher to notify the system
* that animating Activity to PiP has completed and the associated task surface should be
* updated accordingly. This should be called before `finish`
diff --git a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
index 71c6382..b1e38eb 100644
--- a/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
+++ b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java
@@ -54,6 +54,7 @@
private final IActivityTaskManager mActivityTaskManager;
private final String mPackageName;
private final Executor mCallbackExecutor;
+ private final Executor mSystemInteractionExecutor;
// If system loses the callback, our internal cache of original callback will also get cleared.
private final Map<Object, Callback> mPendingCallbacks =
@@ -63,6 +64,7 @@
mActivityTaskManager = ActivityTaskManager.getService();
mPackageName = context.getApplicationContext().getPackageName();
mCallbackExecutor = Executors.MAIN_EXECUTOR;
+ mSystemInteractionExecutor = Executors.UI_HELPER_EXECUTOR;
}
/**
@@ -71,13 +73,16 @@
* @param taskId to query for the content.
* @param callback to call when the content is available, called on the main thread.
*/
- public void requestAssistContent(int taskId, Callback callback) {
- try {
- mActivityTaskManager.requestAssistDataForTask(
- new AssistDataReceiver(callback, this), taskId, mPackageName);
- } catch (RemoteException e) {
- Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
- }
+ public void requestAssistContent(final int taskId, final Callback callback) {
+ // ActivityTaskManager interaction here is synchronous, so call off the main thread.
+ mSystemInteractionExecutor.execute(() -> {
+ try {
+ mActivityTaskManager.requestAssistDataForTask(
+ new AssistDataReceiver(callback, this), taskId, mPackageName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
+ }
+ });
}
private void executeOnMainExecutor(Runnable callback) {
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index badb41a..5cf4f0b 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -78,6 +78,10 @@
}
StateAnimationConfig config = new StateAnimationConfig();
+ if (playWorkspaceRevealAnim) {
+ // WorkspaceRevealAnim handles the depth, so don't interfere.
+ config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
+ }
config.duration = startState.getTransitionDuration(mLauncher);
AnimatorSet stateAnim = stateManager.createAtomicAnimation(
startState, NORMAL, config);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index f897d35..a4c60cf 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -76,7 +76,6 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.UserHandle;
-import android.os.VibrationEffect;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
@@ -133,7 +132,6 @@
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TranslateEdgeEffect;
-import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewPool;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.BaseActivityInterface;
@@ -344,17 +342,6 @@
private static final float INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.55f;
private static final float ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.05f;
- private static final int SNAP_TO_PAGE_VIBRATION_PRIMITIVE =
- Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
- private static final float SNAP_TO_PAGE_VIBRATION_PRIMITIVE_SCALE = 0.4f;
- private static final VibrationEffect SNAP_TO_PAGE_VIBRATION_FALLBACK =
- VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK);
- private static final int EDGE_IMPACT_VIBRATION_PRIMITIVE =
- Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
- private static final float EDGE_IMPACT_VIBRATION_PRIMITIVE_SCALE = 0.8f;
- private static final VibrationEffect EDGE_IMPACT_VIBRATION_FALLBACK =
- VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK);
-
protected final RecentsOrientedState mOrientationState;
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
protected RecentsAnimationController mRecentsAnimationController;
@@ -423,6 +410,7 @@
// TODO(b/187528071): Remove these and replace with a real scrim.
private float mColorTint;
private final int mTintingColor;
+ private ObjectAnimator mTintingAnimator;
private int mOverScrollShift = 0;
@@ -973,8 +961,6 @@
@Override
protected void onPageEndTransition() {
super.onPageEndTransition();
- VibratorWrapper.INSTANCE.get(mContext).vibrate(SNAP_TO_PAGE_VIBRATION_PRIMITIVE,
- SNAP_TO_PAGE_VIBRATION_PRIMITIVE_SCALE, SNAP_TO_PAGE_VIBRATION_FALLBACK);
if (isClearAllHidden()) {
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
}
@@ -1078,13 +1064,6 @@
}
@Override
- protected void onEdgeAbsorbingScroll() {
- super.onEdgeAbsorbingScroll();
- VibratorWrapper.INSTANCE.get(mContext).vibrate(EDGE_IMPACT_VIBRATION_PRIMITIVE,
- EDGE_IMPACT_VIBRATION_PRIMITIVE_SCALE, EDGE_IMPACT_VIBRATION_FALLBACK);
- }
-
- @Override
protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
// Enables swiping to the left or right only if the task overlay is not modal.
if (!isModal()) {
@@ -3715,9 +3694,17 @@
* tasks to be dimmed while other elements in the recents view are left alone.
*/
public void showForegroundScrim(boolean show) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, COLOR_TINT, show ? 0.5f : 0f);
- anim.setAutoCancel(true);
- anim.start();
+ if (!show && mColorTint == 0) {
+ if (mTintingAnimator != null) {
+ mTintingAnimator.cancel();
+ mTintingAnimator = null;
+ }
+ return;
+ }
+
+ mTintingAnimator = ObjectAnimator.ofFloat(this, COLOR_TINT, show ? 0.5f : 0f);
+ mTintingAnimator.setAutoCancel(true);
+ mTintingAnimator.start();
}
/** Tint the RecentsView and TaskViews in to simulate a scrim. */
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index d5816b5..c97225e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -234,7 +234,7 @@
Rect insets = mActivity.getDragLayer().getInsets();
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
int padding = getResources()
- .getDimensionPixelSize(R.dimen.task_card_menu_option_vertical_padding);
+ .getDimensionPixelSize(R.dimen.task_menu_vertical_padding);
params.width = orientationHandler.getTaskMenuWidth(taskView.getThumbnail()) - (2 * padding);
// Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
params.gravity = Gravity.LEFT;
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 02888a1..f730d2d 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -336,12 +336,20 @@
if (mOverlayEnabled != overlayEnabled) {
mOverlayEnabled = overlayEnabled;
- if (mOverlayEnabled) {
- getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
- mPreviewPositionHelper.mIsOrientationChanged);
- } else {
- getTaskOverlay().reset();
- }
+ refreshOverlay();
+ }
+ }
+
+ /**
+ * Potentially re-init the task overlay. Be cautious when calling this as the overlay may
+ * do processing on initialization.
+ */
+ private void refreshOverlay() {
+ if (mOverlayEnabled) {
+ getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
+ mPreviewPositionHelper.mIsOrientationChanged);
+ } else {
+ getTaskOverlay().reset();
}
}
@@ -382,6 +390,8 @@
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateThumbnailMatrix();
+
+ refreshOverlay();
}
private ColorFilter getColorFilter(float dimAmount) {
diff --git a/res/color-night-v31/widgets_picker_scrim.xml b/res/color-night-v31/widgets_picker_scrim.xml
new file mode 100644
index 0000000..be7010b
--- /dev/null
+++ b/res/color-night-v31/widgets_picker_scrim.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_900" android:alpha="0.8" />
+</selector>
diff --git a/res/color-v31/widgets_picker_scrim.xml b/res/color-v31/widgets_picker_scrim.xml
new file mode 100644
index 0000000..648824a
--- /dev/null
+++ b/res/color-v31/widgets_picker_scrim.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_200" android:alpha="0.8" />
+</selector>
diff --git a/res/color/widgets_picker_scrim.xml b/res/color/widgets_picker_scrim.xml
new file mode 100644
index 0000000..1cf97f6
--- /dev/null
+++ b/res/color/widgets_picker_scrim.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#000000" android:alpha="0.32" />
+</selector>
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index ddc9815..9439baf 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -31,7 +31,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/add_item_dialog_background"
- android:padding="24dp"
+ android:paddingTop="24dp"
android:theme="?attr/widgetsTheme"
android:layout_gravity="bottom"
android:orientation="vertical">
@@ -42,6 +42,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
+ android:paddingHorizontal="24dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="24sp"
android:ellipsize="end"
@@ -53,6 +54,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
+ android:paddingHorizontal="24dp"
android:paddingTop="8dp"
android:text="@string/add_item_request_drag_hint"
android:textSize="14sp"
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index a01aa2c..dca3e79 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -25,8 +25,7 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="?android:attr/colorBackground"
- android:elevation="4dp">
+ android:background="?android:attr/colorBackground">
<TextView
android:id="@+id/no_widgets_text"
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 9725b06..b423871 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -250,6 +250,15 @@
forceFinishScroller(true);
}
+ /**
+ * Immediately finishes any overscroll effect and jumps to the end of the scroller animation.
+ */
+ public void abortScrollerAnimation() {
+ mEdgeGlowLeft.finish();
+ mEdgeGlowRight.finish();
+ abortScrollerAnimation(true);
+ }
+
private void abortScrollerAnimation(boolean resetNextPage) {
mScroller.abortAnimation();
// We need to clean up the next page here to avoid computeScrollHelper from
@@ -479,11 +488,9 @@
if (newPos < mMinScroll && oldPos >= mMinScroll) {
mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
mScroller.abortAnimation();
- onEdgeAbsorbingScroll();
} else if (newPos > mMaxScroll && oldPos <= mMaxScroll) {
mEdgeGlowRight.onAbsorb((int) mScroller.getCurrVelocity());
mScroller.abortAnimation();
- onEdgeAbsorbingScroll();
}
}
@@ -1334,13 +1341,6 @@
protected void onNotSnappingToPageInFreeScroll() { }
- /**
- * Called when the view edges absorb part of the scroll. Subclasses can override this
- * to provide custom behavior during animation.
- */
- protected void onEdgeAbsorbingScroll() {
- }
-
protected boolean shouldFlingForVelocity(int velocity) {
float threshold = mAllowEasyFling ? mEasyFlingThresholdVelocity : mFlingThresholdVelocity;
return Math.abs(velocity) > threshold;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 98d80fe..d136cda 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -103,6 +103,7 @@
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OverlayEdgeEffect;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperOffsetInterpolator;
import com.android.launcher3.widget.LauncherAppWidgetHost;
@@ -426,10 +427,9 @@
// When a accessible drag is started by the folder, we only allow rearranging withing the
// folder.
boolean addNewPage = !(options.isAccessibleDrag && dragObject.dragSource != this);
-
if (addNewPage) {
mDeferRemoveExtraEmptyScreen = false;
- addExtraEmptyScreenOnDrag();
+ addExtraEmptyScreenOnDrag(dragObject);
if (dragObject.dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
&& dragObject.dragSource != this) {
@@ -636,12 +636,19 @@
return newScreen;
}
- public void addExtraEmptyScreenOnDrag() {
+ private void addExtraEmptyScreenOnDrag(DragObject dragObject) {
boolean lastChildOnScreen = false;
boolean childOnFinalScreen = false;
if (mDragSourceInternal != null) {
- if (mDragSourceInternal.getChildCount() == 1) {
+ // When the drag view content is a LauncherAppWidgetHostView, we should increment the
+ // drag source child count by 1 because the widget in drag has been detached from its
+ // original parent, ShortcutAndWidgetContainer, and reattached to the DragView.
+ int dragSourceChildCount =
+ dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView
+ ? mDragSourceInternal.getChildCount() + 1
+ : mDragSourceInternal.getChildCount();
+ if (dragSourceChildCount == 1) {
lastChildOnScreen = true;
}
CellLayout cl = (CellLayout) mDragSourceInternal.getParent();
@@ -1921,10 +1928,16 @@
if (droppedOnOriginalCellDuringTransition) {
// Animate the item to its original position, while simultaneously exiting
// spring-loaded mode so the page meets the icon where it was picked up.
+ final RunnableList callbackList = new RunnableList();
+ final Runnable onCompleteCallback = onCompleteRunnable;
mLauncher.getDragController().animateDragViewToOriginalPosition(
- onCompleteRunnable, cell,
+ /* onComplete= */ callbackList::executeAllAndDestroy, cell,
SPRING_LOADED.getTransitionDuration(mLauncher));
- mLauncher.getStateManager().goToState(NORMAL);
+ mLauncher.getStateManager().goToState(NORMAL, /* delay= */ 0,
+ onCompleteCallback == null
+ ? null
+ : forSuccessCallback(
+ () -> callbackList.add(onCompleteCallback)));
mLauncher.getDropTargetBar().onDragEnd();
parent.onDropChild(cell);
return;
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 5dae5a6..b4288ce 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -59,6 +59,7 @@
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.views.AbstractSlideInView;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.AddItemWidgetsBottomSheet;
import com.android.launcher3.widget.LauncherAppWidgetHost;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.NavigableAppWidgetHostView;
@@ -89,6 +90,7 @@
private LauncherAppState mApp;
private InvariantDeviceProfile mIdp;
private BaseDragLayer<AddItemActivity> mDragLayer;
+ private AddItemWidgetsBottomSheet mSlideInView;
private WidgetCell mWidgetCell;
@@ -124,8 +126,6 @@
mDragLayer = findViewById(R.id.add_item_drag_layer);
mDragLayer.recreateControllers();
mDragLayer.setInsets(mDeviceProfile.getInsets());
- AbstractSlideInView<AddItemActivity> slideInView = findViewById(R.id.add_item_bottom_sheet);
- slideInView.addOnCloseListener(this);
mWidgetCell = findViewById(R.id.widget_cell);
if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
@@ -151,6 +151,9 @@
TextView widgetAppName = findViewById(R.id.widget_appName);
widgetAppName.setText(getApplicationInfo().labelRes);
+ mSlideInView = findViewById(R.id.add_item_bottom_sheet);
+ mSlideInView.addOnCloseListener(this);
+ mSlideInView.show();
setupNavBarColor();
}
@@ -279,7 +282,7 @@
*/
public void onCancelClick(View v) {
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED);
- finish();
+ mSlideInView.close(/* animate= */ true);
}
/**
@@ -290,7 +293,7 @@
ItemInstallQueue.INSTANCE.get(this).queueItem(mRequest.getShortcutInfo());
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY);
mRequest.accept();
- finish();
+ mSlideInView.close(/* animate= */ true);
return;
}
@@ -313,7 +316,7 @@
mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
mRequest.accept(mWidgetOptions);
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY);
- finish();
+ mSlideInView.close(/* animate= */ true);
}
@Override
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 8ca157b..e4f5539 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -1,6 +1,7 @@
package com.android.launcher3.graphics;
import static com.android.launcher3.Utilities.getPrefs;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS;
import static com.android.launcher3.util.Themes.isThemedIconEnabled;
@@ -18,7 +19,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
-import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.util.ArrayMap;
@@ -217,7 +217,8 @@
Bundle result = new Bundle();
result.putParcelable(KEY_SURFACE_PACKAGE, renderer.getSurfacePackage());
- Messenger messenger = new Messenger(new Handler(Looper.getMainLooper(), observer));
+ Messenger messenger =
+ new Messenger(new Handler(UI_HELPER_EXECUTOR.getLooper(), observer));
Message msg = Message.obtain();
msg.replyTo = messenger;
result.putParcelable(KEY_CALLBACK, msg);
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 14bf6c2..b0defd4 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -21,19 +21,15 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
-import android.media.AudioAttributes;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
-import com.android.launcher3.Utilities;
-
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
*/
@@ -43,11 +39,6 @@
public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
new MainThreadInitializedObject<>(VibratorWrapper::new);
- public static final AudioAttributes VIBRATION_ATTRS = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .build();
-
public static final VibrationEffect EFFECT_CLICK =
createPredefined(VibrationEffect.EFFECT_CLICK);
@@ -90,24 +81,4 @@
UI_HELPER_EXECUTOR.execute(() -> mVibrator.vibrate(vibrationEffect));
}
}
-
- /**
- * Vibrates with a single primitive, if supported, or use a fallback effect instead. This only
- * vibrates if haptic feedback is available and enabled.
- */
- @SuppressLint("NewApi")
- public void vibrate(int primitiveId, float primitiveScale, VibrationEffect fallbackEffect) {
- if (mHasVibrator && mIsHapticFeedbackEnabled) {
- UI_HELPER_EXECUTOR.execute(() -> {
- if (Utilities.ATLEAST_R && primitiveId >= 0
- && mVibrator.areAllPrimitivesSupported(primitiveId)) {
- mVibrator.vibrate(VibrationEffect.startComposition()
- .addPrimitive(primitiveId, primitiveScale)
- .compose(), VIBRATION_ATTRS);
- } else {
- mVibrator.vibrate(fallbackEffect, VIBRATION_ATTRS);
- }
- });
- }
- }
}
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
index e69cb5b..c6fa98a 100644
--- a/src/com/android/launcher3/views/WidgetsEduView.java
+++ b/src/com/android/launcher3/views/WidgetsEduView.java
@@ -35,8 +35,6 @@
private static final int DEFAULT_CLOSE_DURATION = 200;
- protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
-
private Rect mInsets = new Rect();
private View mEduView;
@@ -87,7 +85,7 @@
@Override
protected int getScrimColor(Context context) {
- return FINAL_SCRIM_BG_COLOR;
+ return context.getResources().getColor(R.color.widgets_picker_scrim);
}
@Override
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
index 9e08303..804973f 100644
--- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -23,8 +23,11 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.view.ViewParent;
import com.android.launcher3.Insettable;
+import com.android.launcher3.R;
import com.android.launcher3.dragndrop.AddItemActivity;
import com.android.launcher3.views.AbstractSlideInView;
@@ -48,6 +51,17 @@
mContent = this;
mInsets = new Rect();
mCurrentConfiguration = new Configuration(getResources().getConfiguration());
+ }
+
+ /**
+ * Attaches to activity container and animates open the bottom sheet.
+ */
+ public void show() {
+ ViewParent parent = getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(this);
+ }
+ attachToContainer();
animateOpen();
}
@@ -95,4 +109,9 @@
}
mCurrentConfiguration.updateFrom(newConfig);
}
+
+ @Override
+ protected int getScrimColor(Context context) {
+ return context.getResources().getColor(R.color.widgets_picker_scrim);
+ }
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index e6791c3..edd42b4 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.widget;
-import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
@@ -62,8 +60,7 @@
}
protected int getScrimColor(Context context) {
- int alpha = context.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
- return setColorAlphaBound(context.getColor(R.color.wallpaper_popup_scrim), alpha);
+ return context.getResources().getColor(R.color.widgets_picker_scrim);
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 7963431..3936ec8 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -25,6 +25,7 @@
import android.view.ViewGroup;
import android.widget.TableRow;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
@@ -48,8 +49,10 @@
import java.util.Comparator;
import java.util.List;
import java.util.Map;
+import java.util.OptionalInt;
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Recycler view adapter for the widget tray.
@@ -87,6 +90,7 @@
|| new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
.equals(mWidgetsContentVisiblePackageUserKey);
@Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
+ @Nullable private RecyclerView mRecyclerView;
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache,
@@ -106,6 +110,16 @@
layoutInflater, /*onHeaderClickListener=*/ this, /* listAdapter= */ this));
}
+ @Override
+ public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
+ mRecyclerView = recyclerView;
+ }
+
+ @Override
+ public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
+ mRecyclerView = null;
+ }
+
public void setFilter(Predicate<WidgetsListBaseEntry> filter) {
mFilter = filter;
}
@@ -168,12 +182,10 @@
mAllEntries.forEach(entry -> {
if (entry instanceof WidgetsListHeaderEntry) {
((WidgetsListHeaderEntry) entry).setIsWidgetListShown(
- new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
- .equals(mWidgetsContentVisiblePackageUserKey));
+ isHeaderForVisibleContent(entry));
} else if (entry instanceof WidgetsListSearchHeaderEntry) {
((WidgetsListSearchHeaderEntry) entry).setIsWidgetListShown(
- new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
- .equals(mWidgetsContentVisiblePackageUserKey));
+ isHeaderForVisibleContent(entry));
}
});
List<WidgetsListBaseEntry> newVisibleEntries = mAllEntries.stream()
@@ -183,6 +195,13 @@
mDiffReporter.process(mVisibleEntries, newVisibleEntries, mRowComparator);
}
+ private boolean isHeaderForVisibleContent(WidgetsListBaseEntry entry) {
+ return (entry instanceof WidgetsListHeaderEntry
+ || entry instanceof WidgetsListSearchHeaderEntry)
+ && new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
+ .equals(mWidgetsContentVisiblePackageUserKey);
+ }
+
/**
* Resets any expanded widget header.
*/
@@ -247,12 +266,40 @@
if (showWidgets) {
mWidgetsContentVisiblePackageUserKey = packageUserKey;
updateVisibleEntries();
+ // Scroll the layout manager to the header position to keep it anchored to the same
+ // position.
+ scrollToSelectedHeaderPosition();
} else if (packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) {
mWidgetsContentVisiblePackageUserKey = null;
updateVisibleEntries();
}
}
+ private void scrollToSelectedHeaderPosition() {
+ OptionalInt selectedHeaderPosition =
+ IntStream.range(0, mVisibleEntries.size())
+ .filter(index -> isHeaderForVisibleContent(mVisibleEntries.get(index)))
+ .findFirst();
+ RecyclerView.LayoutManager layoutManager =
+ mRecyclerView == null ? null : mRecyclerView.getLayoutManager();
+ if (!selectedHeaderPosition.isPresent() || layoutManager == null) {
+ return;
+ }
+
+ // Scroll to the selected header position. LinearLayoutManager scrolls the minimum distance
+ // necessary, so this will keep the selected header in place during clicks, without
+ // interrupting the animation.
+ int position = selectedHeaderPosition.getAsInt();
+ if (position == mVisibleEntries.size() - 2) {
+ // If the selected header is in the last position (-1 for the content), then scroll to
+ // the final position so the last list of widgets will show.
+ layoutManager.scrollToPosition(mVisibleEntries.size() - 1);
+ } else {
+ // Otherwise, scroll to the position of the selected header.
+ layoutManager.scrollToPosition(position);
+ }
+ }
+
/**
* Sets the max horizontal spans that are allowed for grouping more than one widgets in a table
* row.
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index e30e245..090362b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -154,8 +154,25 @@
return -1;
}
- View child = getChildAt(0);
- int rowIndex = getChildPosition(child);
+ int rowIndex = -1;
+ View child = null;
+
+ LayoutManager layoutManager = getLayoutManager();
+ if (layoutManager instanceof LinearLayoutManager) {
+ // Use the LayoutManager as the source of truth for visible positions. During
+ // animations, the view group child may not correspond to the visible views that appear
+ // at the top.
+ rowIndex = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+ child = layoutManager.findViewByPosition(rowIndex);
+ }
+
+ if (child == null) {
+ // If the layout manager returns null for any reason, which can happen before layout
+ // has occurred for the position, then look at the child of this view as a ViewGroup.
+ child = getChildAt(0);
+ rowIndex = getChildPosition(child);
+ }
+
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (view instanceof TableLayout) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 4cf52f0..c99a81f 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -105,7 +105,7 @@
static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
private final String mLauncherPackage;
- private final boolean mIsLauncher3;
+ private Boolean mIsLauncher3;
private long mTestStartTime = -1;
// Types for launcher containers that the user is interacting with. "Background" is a
@@ -206,7 +206,6 @@
public LauncherInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
mDevice = UiDevice.getInstance(instrumentation);
- mIsLauncher3 = "com.android.launcher3".equals(getLauncherPackageName());
// Launcher should run in test harness so that custom accessibility protocol between
// Launcher and TAPL is enabled. In-process tests enable this protocol with a direct call
@@ -1422,6 +1421,9 @@
}
boolean isLauncher3() {
+ if (mIsLauncher3 == null) {
+ mIsLauncher3 = "com.android.launcher3".equals(getLauncherPackageName());
+ }
return mIsLauncher3;
}