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

Commit daf42757 authored by Yeabkal Wubshit's avatar Yeabkal Wubshit Committed by Android (Google) Code Review
Browse files

Merge changes from topics "scroll_feedback_api_updates_2",...

Merge changes from topics "scroll_feedback_api_updates_2", "scroll_feedback_api_updates_3" into main

* changes:
  Hide haptic feedback ViewConfiguration APIs
  Create default ScrollFeedbackProvider creator
parents 7534b4dc 82d5bdda
Loading
Loading
Loading
Loading
+4 −12
Original line number Diff line number Diff line
@@ -50137,13 +50137,6 @@ package android.view {
    field public static final int VIRTUAL_KEY_RELEASE = 8; // 0x8
  }
  @FlaggedApi("android.view.flags.scroll_feedback_api") public class HapticScrollFeedbackProvider implements android.view.ScrollFeedbackProvider {
    ctor public HapticScrollFeedbackProvider(@NonNull android.view.View);
    method public void onScrollLimit(int, int, int, boolean);
    method public void onScrollProgress(int, int, int, int);
    method public void onSnapToItem(int, int, int);
  }
  public class InflateException extends java.lang.RuntimeException {
    ctor public InflateException();
    ctor public InflateException(String, Throwable);
@@ -51310,9 +51303,10 @@ package android.view {
  }
  @FlaggedApi("android.view.flags.scroll_feedback_api") public interface ScrollFeedbackProvider {
    method public void onScrollLimit(int, int, int, boolean);
    method public void onScrollProgress(int, int, int, int);
    method public void onSnapToItem(int, int, int);
    method @FlaggedApi("android.view.flags.scroll_feedback_api") @NonNull public static android.view.ScrollFeedbackProvider createProvider(@NonNull android.view.View);
    method @FlaggedApi("android.view.flags.scroll_feedback_api") public void onScrollLimit(int, int, int, boolean);
    method @FlaggedApi("android.view.flags.scroll_feedback_api") public void onScrollProgress(int, int, int, int);
    method @FlaggedApi("android.view.flags.scroll_feedback_api") public void onSnapToItem(int, int, int);
  }
  public class SearchEvent {
@@ -52594,7 +52588,6 @@ package android.view {
    method @Deprecated public static int getEdgeSlop();
    method @Deprecated public static int getFadingEdgeLength();
    method @Deprecated public static long getGlobalActionKeyTimeout();
    method @FlaggedApi("android.view.flags.scroll_feedback_api") public int getHapticScrollFeedbackTickInterval(int, int, int);
    method public static int getJumpTapTimeout();
    method public static int getKeyRepeatDelay();
    method public static int getKeyRepeatTimeout();
@@ -52634,7 +52627,6 @@ package android.view {
    method @Deprecated public static int getWindowTouchSlop();
    method public static long getZoomControlsTimeout();
    method public boolean hasPermanentMenuKey();
    method @FlaggedApi("android.view.flags.scroll_feedback_api") public boolean isHapticScrollFeedbackEnabled(int, int, int);
    method public boolean shouldShowMenuShortcutsWhenKeyboardPresent();
  }
+5 −17
Original line number Diff line number Diff line
@@ -16,16 +16,10 @@

package android.view;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.view.flags.Flags;

import com.android.internal.annotations.VisibleForTesting;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * {@link ScrollFeedbackProvider} that performs haptic feedback when scrolling.
 *
@@ -36,16 +30,12 @@ import java.lang.annotation.RetentionPolicy;
 * methods in this class. To check if your input device ID, source, and motion axis are valid for
 * haptic feedback, you can use the
 * {@link ViewConfiguration#isHapticScrollFeedbackEnabled(int, int, int)} API.
 *
 * @hide
 */
@FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {
    private static final String TAG = "HapticScrollFeedbackProvider";

    /** @hide */
    @IntDef(value = {MotionEvent.AXIS_SCROLL})
    @Retention(RetentionPolicy.SOURCE)
    public @interface HapticScrollFeedbackAxis {}

    private static final int TICK_INTERVAL_NO_TICK = 0;
    private static final boolean INITIAL_END_OF_LIST_HAPTICS_ENABLED = false;

@@ -89,8 +79,7 @@ public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {
    }

    @Override
    public void onScrollProgress(
            int inputDeviceId, int source, @HapticScrollFeedbackAxis int axis, int deltaInPixels) {
    public void onScrollProgress(int inputDeviceId, int source, int axis, int deltaInPixels) {
        maybeUpdateCurrentConfig(inputDeviceId, source, axis);
        if (!mHapticScrollFeedbackEnabled) {
            return;
@@ -117,8 +106,7 @@ public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {
    }

    @Override
    public void onScrollLimit(
            int inputDeviceId, int source, @HapticScrollFeedbackAxis int axis, boolean isStart) {
    public void onScrollLimit(int inputDeviceId, int source, int axis, boolean isStart) {
        maybeUpdateCurrentConfig(inputDeviceId, source, axis);
        if (!mHapticScrollFeedbackEnabled) {
            return;
@@ -135,7 +123,7 @@ public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {
    }

    @Override
    public void onSnapToItem(int inputDeviceId, int source, @HapticScrollFeedbackAxis int axis) {
    public void onSnapToItem(int inputDeviceId, int source, int axis) {
        maybeUpdateCurrentConfig(inputDeviceId, source, axis);
        if (!mHapticScrollFeedbackEnabled) {
            return;
+23 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.view;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.view.flags.Flags;

/**
@@ -62,23 +63,37 @@ import android.view.flags.Flags;
 * </ul>
 *
 * <b>Note</b> that not all valid input device source and motion axis inputs are necessarily
 * supported for scroll feedback. If you are implementing this interface, provide clear
 * documentation in your implementation class about which input device source and motion axis are
 * supported for your specific implementation. If you are using one of the implementations of this
 * interface, please refer to the documentation of the implementation for details on which input
 * device source and axis are supported.
 * supported for scroll feedback; the implementation may choose to provide no feedback for some
 * valid input device source and motion axis arguments.
 */
@FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
public interface ScrollFeedbackProvider {

    /**
     * Call this when the view has snapped to an item.
     * Creates a {@link ScrollFeedbackProvider} implementation for this device.
     *
     * <p>Use a feedback provider created by this method, unless you intend to use your custom
     * scroll feedback providing logic. This allows your use cases to generate scroll feedback that
     * is consistent with the rest of the use cases on the device.
     *
     * @param view the {@link View} for which to provide scroll feedback.
     * @return the default {@link ScrollFeedbackProvider} implementation for the device.
     */
    @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
    @NonNull
    static ScrollFeedbackProvider createProvider(@NonNull View view) {
        return new HapticScrollFeedbackProvider(view);
    }

    /**
     * Call this when the view has snapped to an item.
     *
     * @param inputDeviceId the ID of the {@link InputDevice} that generated the motion triggering
     *          the snap.
     * @param source the input source of the motion causing the snap.
     * @param axis the axis of {@code event} that caused the item to snap.
     */
    @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
    void onSnapToItem(int inputDeviceId, int source, int axis);

    /**
@@ -99,6 +114,7 @@ public interface ScrollFeedbackProvider {
     *                "start" for some views may be at the bottom of a scrolling list, while it may
     *                be at the top of scrolling list for others.
     */
    @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
    void onScrollLimit(int inputDeviceId, int source, int axis, boolean isStart);

    /**
@@ -122,5 +138,6 @@ public interface ScrollFeedbackProvider {
     * @param axis the axis of {@code event} that caused scroll progress.
     * @param deltaInPixels the amount of scroll progress, in pixels.
     */
    @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
    void onScrollProgress(int inputDeviceId, int source, int axis, int deltaInPixels);
}
+6 −14
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package android.view;

import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.TestApi;
@@ -1272,12 +1271,10 @@ public class ViewConfiguration {
     * @see InputDevice#getMotionRanges()
     * @see InputDevice#getMotionRange(int)
     * @see InputDevice#getMotionRange(int, int)
     *
     * @hide
     */
    @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
    public boolean isHapticScrollFeedbackEnabled(
            int inputDeviceId,
            @HapticScrollFeedbackProvider.HapticScrollFeedbackAxis int axis,
            int source) {
    public boolean isHapticScrollFeedbackEnabled(int inputDeviceId, int axis, int source) {
        if (!isInputDeviceInfoValid(inputDeviceId, axis, source)) return false;

        if (source == InputDevice.SOURCE_ROTARY_ENCODER && axis == MotionEvent.AXIS_SCROLL) {
@@ -1318,12 +1315,10 @@ public class ViewConfiguration {
     *      returns {@code Integer.MAX_VALUE}.
     *
     * @see #isHapticScrollFeedbackEnabled(int, int, int)
     *
     * @hide
     */
    @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API)
    public int getHapticScrollFeedbackTickInterval(
            int inputDeviceId,
            @HapticScrollFeedbackProvider.HapticScrollFeedbackAxis int axis,
            int source) {
    public int getHapticScrollFeedbackTickInterval(int inputDeviceId, int axis, int source) {
        if (!mRotaryEncoderHapticScrollFeedbackEnabled) {
            return NO_HAPTIC_SCROLL_TICK_INTERVAL;
        }
@@ -1343,9 +1338,6 @@ public class ViewConfiguration {
     * Checks if the View-based haptic scroll feedback implementation is enabled for
     * {@link InputDevice#SOURCE_ROTARY_ENCODER}s.
     *
     * <p>If this method returns {@code true}, the {@link HapticScrollFeedbackProvider} will be
     * muted for rotary encoders in favor of View's scroll haptics implementation.
     *
     * @hide
     */
    public boolean isViewBasedRotaryEncoderHapticScrollFeedbackEnabled() {
+58 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.
 */

package android.view;

import static com.google.common.truth.Truth.assertThat;

import android.content.Context;
import android.platform.test.annotations.Presubmit;

import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
@Presubmit
public final class ScrollFeedbackProviderTest {
    private final Context mContext = InstrumentationRegistry.getContext();

    @Test
    public void testDefaultProviderType() {
        View view = new View(mContext);

        ScrollFeedbackProvider provider = ScrollFeedbackProvider.createProvider(view);

        assertThat(provider).isInstanceOf(HapticScrollFeedbackProvider.class);
    }

    @Test
    public void testDefaultProvider_createsDistinctProvidesOnMultipleCalls() {
        View view1 = new View(mContext);
        View view2 = new View(mContext);

        ScrollFeedbackProvider view1Provider1 = ScrollFeedbackProvider.createProvider(view1);
        ScrollFeedbackProvider view1Provider2 = ScrollFeedbackProvider.createProvider(view1);
        ScrollFeedbackProvider view2Provider = ScrollFeedbackProvider.createProvider(view2);

        assertThat(view1Provider1 == view1Provider2).isFalse();
        assertThat(view1Provider1 == view2Provider).isFalse();
    }
}