mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 08:16:49 +00:00
Merge "Introduces haptic feedback to launcher overview" into sc-v2-dev am: 8f0de5d711
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/15177217 Change-Id: I8faf92aa56d0d4b663d7dd1cb8eca36344925ba9
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
determines how many thumbnails will be fetched in the background. -->
|
||||
<integer name="recentsThumbnailCacheSize">3</integer>
|
||||
<integer name="recentsIconCacheSize">12</integer>
|
||||
<integer name="recentsScrollHapticMinGapMillis">20</integer>
|
||||
|
||||
<!-- Assistant Gesture -->
|
||||
<integer name="assistant_gesture_min_time_threshold">200</integer>
|
||||
|
||||
@@ -24,7 +24,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
@@ -38,11 +38,11 @@ import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.quickstep.util.OverviewToHomeAnim;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
|
||||
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
|
||||
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
|
||||
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
|
||||
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
|
||||
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
|
||||
@@ -67,14 +67,15 @@ import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.touch.BaseSwipeDetector;
|
||||
import com.android.launcher3.touch.BothAxesSwipeDetector;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
import com.android.quickstep.util.WorkspaceRevealAnim;
|
||||
import com.android.quickstep.views.LauncherRecentsView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* Handles quick switching to a recent task from the home screen. To give as much flexibility to
|
||||
@@ -398,6 +399,14 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
|
||||
nonOverviewAnim.setFloatValues(startProgress, endProgress);
|
||||
mNonOverviewAnim.dispatchOnStart();
|
||||
}
|
||||
if (targetState == QUICK_SWITCH) {
|
||||
// Navigating to quick switch, add scroll feedback since the first time is not
|
||||
// considered a scroll by the RecentsView.
|
||||
VibratorWrapper.INSTANCE.get(mLauncher).vibrate(
|
||||
RecentsView.SCROLL_VIBRATION_PRIMITIVE,
|
||||
RecentsView.SCROLL_VIBRATION_PRIMITIVE_SCALE,
|
||||
RecentsView.SCROLL_VIBRATION_FALLBACK);
|
||||
}
|
||||
|
||||
nonOverviewAnim.setDuration(Math.max(xDuration, yDuration));
|
||||
mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState));
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.os.SystemClock;
|
||||
import android.os.VibrationEffect;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
@@ -41,6 +42,7 @@ import com.android.launcher3.util.FlingBlockCheck;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
|
||||
@@ -55,6 +57,12 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
private static final long MIN_TASK_DISMISS_ANIMATION_DURATION = 300;
|
||||
private static final long MAX_TASK_DISMISS_ANIMATION_DURATION = 600;
|
||||
|
||||
public static final int TASK_DISMISS_VIBRATION_PRIMITIVE =
|
||||
Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
|
||||
public static final float TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE = 1f;
|
||||
public static final VibrationEffect TASK_DISMISS_VIBRATION_FALLBACK =
|
||||
VibratorWrapper.EFFECT_TEXTURE_TICK;
|
||||
|
||||
protected final T mActivity;
|
||||
private final SingleAxisSwipeDetector mDetector;
|
||||
private final RecentsView mRecentsView;
|
||||
@@ -334,10 +342,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
fling = false;
|
||||
}
|
||||
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
|
||||
boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
|
||||
float progress = mCurrentAnimation.getProgressFraction();
|
||||
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
|
||||
if (fling) {
|
||||
boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
|
||||
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
|
||||
} else {
|
||||
goingToEnd = interpolatedProgress > SUCCESS_TRANSITION_PROGRESS;
|
||||
@@ -357,6 +365,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
|
||||
velocity * orientationHandler.getSecondaryTranslationDirectionFactor(),
|
||||
mEndDisplacement, animationDuration);
|
||||
if (goingUp && goingToEnd) {
|
||||
VibratorWrapper.INSTANCE.get(mActivity).vibrate(TASK_DISMISS_VIBRATION_PRIMITIVE,
|
||||
TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE, TASK_DISMISS_VIBRATION_FALLBACK);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearState() {
|
||||
|
||||
@@ -36,7 +36,6 @@ import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
|
||||
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
|
||||
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
|
||||
@@ -46,6 +45,7 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
|
||||
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_CANCELED;
|
||||
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
|
||||
@@ -92,7 +92,6 @@ import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.tracing.InputConsumerProto;
|
||||
import com.android.launcher3.tracing.SwipeHandlerProto;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
|
||||
import com.android.quickstep.GestureState.GestureEndTarget;
|
||||
@@ -112,6 +111,7 @@ import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
import com.android.quickstep.util.SwipePipToHomeAnimator;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
@@ -43,7 +43,7 @@ import androidx.dynamicanimation.animation.SpringForce;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
|
||||
/** Forked from platform/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java. */
|
||||
public class EdgeBackGesturePanel extends View {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.quickstep.interaction;
|
||||
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_COMPLETED;
|
||||
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_BAD_ANGLE;
|
||||
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT;
|
||||
@@ -26,6 +25,7 @@ import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestu
|
||||
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION;
|
||||
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_GESTURE_COMPLETED;
|
||||
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE;
|
||||
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
@@ -47,11 +47,11 @@ import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.quickstep.util.NavBarPosition;
|
||||
import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
/** Utility class to handle Home and Assistant gestures. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* 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.
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static android.os.VibrationEffect.createPredefined;
|
||||
import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
|
||||
@@ -21,15 +21,20 @@ import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
|
||||
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;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
|
||||
/**
|
||||
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
|
||||
*/
|
||||
@@ -39,8 +44,15 @@ public class VibratorWrapper {
|
||||
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);
|
||||
public static final VibrationEffect EFFECT_TEXTURE_TICK =
|
||||
VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK);
|
||||
|
||||
/**
|
||||
* Haptic when entering overview.
|
||||
@@ -78,7 +90,27 @@ public class VibratorWrapper {
|
||||
/** Vibrates with the given effect if haptic feedback is available and enabled. */
|
||||
public void vibrate(VibrationEffect vibrationEffect) {
|
||||
if (mHasVibrator && mIsHapticFeedbackEnabled) {
|
||||
UI_HELPER_EXECUTOR.execute(() -> mVibrator.vibrate(vibrationEffect));
|
||||
UI_HELPER_EXECUTOR.execute(() -> mVibrator.vibrate(vibrationEffect, VIBRATION_ATTRS));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,9 @@ import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.os.VibrationEffect;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
@@ -160,6 +162,7 @@ import com.android.quickstep.util.SplitSelectStateController;
|
||||
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
@@ -244,6 +247,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
};
|
||||
|
||||
public static final int SCROLL_VIBRATION_PRIMITIVE =
|
||||
Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
|
||||
public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
|
||||
public static final VibrationEffect SCROLL_VIBRATION_FALLBACK =
|
||||
VibratorWrapper.EFFECT_TEXTURE_TICK;
|
||||
|
||||
/**
|
||||
* Can be used to tint the color of the RecentsView to simulate a scrim that can views
|
||||
* excluded from. Really should be a proper scrim.
|
||||
@@ -397,6 +406,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
protected final ACTIVITY_TYPE mActivity;
|
||||
private final float mFastFlingVelocity;
|
||||
private final int mScrollHapticMinGapMillis;
|
||||
private final RecentsModel mModel;
|
||||
private final int mGridSideMargin;
|
||||
private final ClearAllButton mClearAllButton;
|
||||
@@ -443,6 +453,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private ObjectAnimator mTintingAnimator;
|
||||
|
||||
private int mOverScrollShift = 0;
|
||||
private long mScrollLastHapticTimestamp;
|
||||
|
||||
/**
|
||||
* TODO: Call reloadIdNeeded in onTaskStackChanged.
|
||||
@@ -629,6 +640,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
final int rotation = mActivity.getDisplay().getRotation();
|
||||
mOrientationState.setRecentsRotation(rotation);
|
||||
|
||||
mScrollHapticMinGapMillis = getResources()
|
||||
.getInteger(R.integer.recentsScrollHapticMinGapMillis);
|
||||
mFastFlingVelocity = getResources()
|
||||
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
|
||||
mModel = RecentsModel.INSTANCE.get(context);
|
||||
@@ -1228,6 +1241,25 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEdgeAbsorbingScroll() {
|
||||
vibrateForScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onScrollOverPageChanged() {
|
||||
vibrateForScroll();
|
||||
}
|
||||
|
||||
private void vibrateForScroll() {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
if (now - mScrollLastHapticTimestamp > mScrollHapticMinGapMillis) {
|
||||
mScrollLastHapticTimestamp = now;
|
||||
VibratorWrapper.INSTANCE.get(mContext).vibrate(SCROLL_VIBRATION_PRIMITIVE,
|
||||
SCROLL_VIBRATION_PRIMITIVE_SCALE, SCROLL_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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user