1 /** 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.NonNull; 21 import android.view.flags.Flags; 22 23 /** 24 * Provides feedback to the user for scroll events on a {@link View}. The type of feedback provided 25 * to the user may depend on the {@link InputDevice} that generated the scroll events. 26 * 27 * <p>An example of the type of feedback that this interface may provide is haptic feedback (that 28 * is, tactile feedback that provide the user physical feedback for their scroll). 29 * 30 * <p>The interface provides methods for the client to report different scroll events. The client 31 * should report all scroll events that they want to be considered for scroll feedback using the 32 * respective methods. The interface will process these events and provide scroll feedback based on 33 * its specific feedback implementation. 34 * 35 * <h3>Obtaining the correct arguments for methods in this interface</h3> 36 * 37 * <p>Methods in this interface rely on the provision of valid {@link InputDevice} ID and source, as 38 * well as the {@link MotionEvent} axis that generated a specific scroll event. The 39 * {@link InputDevice} represented by the provided ID must have a {@link InputDevice.MotionRange} 40 * with the provided source and axis. See below for more details on obtaining the right arguments 41 * for your method call. 42 * 43 * <ul> 44 * 45 * <li><p><b>inputDeviceId</b>: should always be the ID of the {@link InputDevice} that generated 46 * the scroll event. If calling this method in response to a {@link MotionEvent}, use the device ID 47 * that is reported by the event, which can be obtained using {@link MotionEvent#getDeviceId()}. 48 * Otherwise, use a valid ID that is obtained from {@link InputDevice#getId()}, or from an 49 * {@link android.hardware.input.InputManager} instance 50 * ({@link android.hardware.input.InputManager#getInputDeviceIds()} gives all the valid input 51 * device IDs). 52 * 53 * <li><p><b>source</b>: should always be the {@link InputDevice} source that generated the scroll 54 * event. Use {@link MotionEvent#getSource()} if calling this method in response to a 55 * {@link MotionEvent}. Otherwise, use a valid source for the {@link InputDevice}. You can use 56 * {@link InputDevice#getMotionRanges()} to get all the {@link InputDevice.MotionRange}s for the 57 * {@link InputDevice}, from which you can derive all the valid sources for the device. 58 * 59 * <li><p><b>axis</b>: should always be the axis whose axis value produced the scroll event. 60 * A {@link MotionEvent} may report data for multiple axes, and each axis may have multiple data 61 * points for different pointers. Use the axis whose movement produced the specific scroll event. 62 * The motion value for an axis can be obtained using {@link MotionEvent#getAxisValue(int)}. 63 * You can use {@link InputDevice#getMotionRanges()} to get all the {@link InputDevice.MotionRange}s 64 * for the {@link InputDevice}, from which you can derive all the valid axes for the device. 65 * 66 * </ul> 67 * 68 * <b>Note</b> that not all valid input device source and motion axis inputs are necessarily 69 * supported for scroll feedback; the implementation may choose to provide no feedback for some 70 * valid input device source and motion axis arguments. 71 */ 72 @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) 73 public interface ScrollFeedbackProvider { 74 75 /** 76 * Creates a {@link ScrollFeedbackProvider} implementation for this device. 77 * 78 * <p>Use a feedback provider created by this method, unless you intend to use your custom 79 * scroll feedback providing logic. This allows your use cases to generate scroll feedback that 80 * is consistent with the rest of the use cases on the device. 81 * 82 * @param view the {@link View} for which to provide scroll feedback. 83 * @return the default {@link ScrollFeedbackProvider} implementation for the device. 84 */ 85 @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) 86 @NonNull createProvider(@onNull View view)87 static ScrollFeedbackProvider createProvider(@NonNull View view) { 88 return new HapticScrollFeedbackProvider(view); 89 } 90 91 /** 92 * Call this when the view has snapped to an item. 93 * 94 * @param inputDeviceId the ID of the {@link InputDevice} that generated the motion triggering 95 * the snap. 96 * @param source the input source of the motion causing the snap. 97 * @param axis the axis of {@code event} that caused the item to snap. 98 */ 99 @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) onSnapToItem(int inputDeviceId, int source, int axis)100 void onSnapToItem(int inputDeviceId, int source, int axis); 101 102 /** 103 * Call this when the view has reached the scroll limit. 104 * 105 * <p>Note that a feedback may not be provided on every call to this method. This interface, for 106 * instance, may provide feedback on every `N`th scroll limit event. For the interface to 107 * properly provide feedback when needed, call this method for each scroll limit event that you 108 * want to be accounted to scroll limit feedback. 109 * 110 * @param inputDeviceId the ID of the {@link InputDevice} that caused scrolling to hit limit. 111 * @param source the input source of the motion that caused scrolling to hit the limit. 112 * @param axis the axis of {@code event} that caused scrolling to hit the limit. 113 * @param isStart {@code true} if scrolling hit limit at the start of the scrolling list, and 114 * {@code false} if the scrolling hit limit at the end of the scrolling list. 115 * <i>start</i> and <i>end<i> in this context are not geometrical references. 116 * Instead, they refer to the start and end of a scrolling experience. As such, 117 * "start" for some views may be at the bottom of a scrolling list, while it may 118 * be at the top of scrolling list for others. 119 */ 120 @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) onScrollLimit(int inputDeviceId, int source, int axis, boolean isStart)121 void onScrollLimit(int inputDeviceId, int source, int axis, boolean isStart); 122 123 /** 124 * Call this when the view has scrolled. 125 * 126 * <p>Different axes have different ways to map their raw axis values to pixels for scrolling. 127 * When calling this method, use the scroll values in pixels by which the view was scrolled; do 128 * not use the raw axis values. That is, use whatever value is passed to one of View's scrolling 129 * methods (example: {@link View#scrollBy(int, int)}). For example, for vertical scrolling on 130 * {@link MotionEvent#AXIS_SCROLL}, convert the raw axis value to the equivalent pixels by using 131 * {@link ViewConfiguration#getScaledVerticalScrollFactor()}, and use that value for this method 132 * call. 133 * 134 * <p>Note that a feedback may not be provided on every call to this method. This interface, for 135 * instance, may provide feedback for every `x` pixels scrolled. For the interface to properly 136 * track scroll progress and provide feedback when needed, call this method for each scroll 137 * event that you want to be accounted to scroll feedback. 138 * 139 * @param inputDeviceId the ID of the {@link InputDevice} that caused scroll progress. 140 * @param source the input source of the motion that caused scroll progress. 141 * @param axis the axis of {@code event} that caused scroll progress. 142 * @param deltaInPixels the amount of scroll progress, in pixels. 143 */ 144 @FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) onScrollProgress(int inputDeviceId, int source, int axis, int deltaInPixels)145 void onScrollProgress(int inputDeviceId, int source, int axis, int deltaInPixels); 146 } 147