Introduces haptic feedback to launcher overview

Haptics introduced at the key moments:

- Task scroll in overview or quick switch, trigger when a new task comes
to the center of the screen;
- Task scroll in overview when overscroll animation is triggered;
- Task dismissed in overview;

There is also a configured min gap between two scroll haptics set to
20ms to prevent fast scrolls from creating a chain of cancelled effects.

Fix: 182382085
Test: manual
Change-Id: I43c0f8c879a06f317e8a660240dafb7f7abe79f7
This commit is contained in:
Lais Andrade
2021-06-04 18:20:30 +01:00
parent 32e573162d
commit cc5c8843df
10 changed files with 130 additions and 13 deletions

View File

@@ -108,6 +108,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
// relative scroll position unchanged in updateCurrentPageScroll. Cleared when snapping to a
// page.
protected int mCurrentPageScrollDiff;
// The current page the PagedView is scrolling over on it's way to the destination page.
protected int mCurrentScrollOverPage;
@ViewDebug.ExportedProperty(category = "launcher")
protected int mNextPage = INVALID_PAGE;
@@ -180,6 +182,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
mScroller = new OverScroller(context, SCROLL);
mCurrentPage = 0;
mCurrentScrollOverPage = 0;
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
@@ -437,6 +440,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
}
int prevPage = overridePrevPage != INVALID_PAGE ? overridePrevPage : mCurrentPage;
mCurrentPage = validateNewPage(currentPage);
mCurrentScrollOverPage = mCurrentPage;
updateCurrentPageScroll();
notifyPageSwitchListener(prevPage);
invalidate();
@@ -557,9 +561,11 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
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();
}
}
@@ -577,6 +583,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
sendScrollAccessibilityEvent();
int prevPage = mCurrentPage;
mCurrentPage = validateNewPage(mNextPage);
mCurrentScrollOverPage = mCurrentPage;
mNextPage = INVALID_PAGE;
notifyPageSwitchListener(prevPage);
@@ -837,6 +844,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
public void onViewRemoved(View child) {
super.onViewRemoved(child);
mCurrentPage = validateNewPage(mCurrentPage);
mCurrentScrollOverPage = mCurrentPage;
dispatchPageCountChanged();
}
@@ -1408,6 +1416,20 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
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() {
}
/**
* Called when the current page closest to the center of the screen changes as part of the
* scroll. Subclasses can override this to provide custom behavior during scroll.
*/
protected void onScrollOverPageChanged() {
}
protected boolean shouldFlingForVelocity(int velocity) {
float threshold = mAllowEasyFling ? mEasyFlingThresholdVelocity : mFlingThresholdVelocity;
return Math.abs(velocity) > threshold;
@@ -1691,6 +1713,15 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
return mAllowOverScroll;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
int newDestinationPage = getDestinationPage();
if (newDestinationPage >= 0 && newDestinationPage != mCurrentScrollOverPage) {
mCurrentScrollOverPage = newDestinationPage;
onScrollOverPageChanged();
}
}
@Override
public CharSequence getAccessibilityClassName() {
// Some accessibility services have special logic for ScrollView. Since we provide same