Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1858afa authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add haptic feedback to Launcher recent apps scrolling" into sc-dev

parents fa7c98ee b1ef5e5c
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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);
        }
@@ -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.
+9 −0
Original line number Diff line number Diff line
@@ -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();
                }
            }

@@ -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;
+29 −0
Original line number Diff line number Diff line
@@ -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.
 */
@@ -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);

@@ -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);
                }
            });
        }
    }
}