Loading quickstep/src/com/android/quickstep/views/RecentsView.java +22 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ import android.graphics.Typeface; 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; Loading Loading @@ -132,6 +133,7 @@ import com.android.launcher3.util.SplitConfigurationOptions; 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; Loading Loading @@ -342,6 +344,17 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T 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; Loading Loading @@ -960,6 +973,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T @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); } Loading Loading @@ -1062,6 +1077,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } } @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. Loading src/com/android/launcher3/PagedView.java +9 −0 Original line number Diff line number Diff line Loading @@ -479,9 +479,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(); } } Loading Loading @@ -1332,6 +1334,13 @@ 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() { } protected boolean shouldFlingForVelocity(int velocity) { float threshold = mAllowEasyFling ? mEasyFlingThresholdVelocity : mFlingThresholdVelocity; return Math.abs(velocity) > threshold; Loading src/com/android/launcher3/util/VibratorWrapper.java +29 −0 Original line number Diff line number Diff line Loading @@ -21,15 +21,19 @@ 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; /** * Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary. */ Loading @@ -39,6 +43,11 @@ 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); Loading Loading @@ -81,4 +90,24 @@ public class VibratorWrapper { 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); } }); } } } Loading
quickstep/src/com/android/quickstep/views/RecentsView.java +22 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ import android.graphics.Typeface; 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; Loading Loading @@ -132,6 +133,7 @@ import com.android.launcher3.util.SplitConfigurationOptions; 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; Loading Loading @@ -342,6 +344,17 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T 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; Loading Loading @@ -960,6 +973,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T @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); } Loading Loading @@ -1062,6 +1077,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } } @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. Loading
src/com/android/launcher3/PagedView.java +9 −0 Original line number Diff line number Diff line Loading @@ -479,9 +479,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(); } } Loading Loading @@ -1332,6 +1334,13 @@ 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() { } protected boolean shouldFlingForVelocity(int velocity) { float threshold = mAllowEasyFling ? mEasyFlingThresholdVelocity : mFlingThresholdVelocity; return Math.abs(velocity) > threshold; Loading
src/com/android/launcher3/util/VibratorWrapper.java +29 −0 Original line number Diff line number Diff line Loading @@ -21,15 +21,19 @@ 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; /** * Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary. */ Loading @@ -39,6 +43,11 @@ 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); Loading Loading @@ -81,4 +90,24 @@ public class VibratorWrapper { 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); } }); } } }