Rotary input

Some Wear OS devices contain a physical rotating side button. When the user turns the button, your app's current view should scroll up or down. This type of input is called rotary input.

Many scrollable containers, like ScrollView, ListView, HorizontalScrollView, and WearableRecyclerView, support rotary input without requiring any Wear OS-specific code, if these containers have focus. Having focus is an important prerequisite, because on Android 9 (API level 28) and higher, views don't implicitly receive focus.

Focus best practices

To respond to rotary input events, a scrollable container must have focus. The following are best practices around responding to rotary input events:

  • By default, launching an activity or even tapping on a view does not give it focus, even if it is focusable. To give your view focus, the view must use the <requestFocus /> tag or manually call View.requestFocus().
  • Mark custom scrollable views as focusable using both android:focusable="true" and android:focusableInTouchMode="true".
  • Rotary input events are sent only to the focused view. These events do not bubble up the view hierarchy. If there is no focused view, or if the focused view returns false from View.onGenericMotionEvent(), then the event is sent to Activity.onGenericMotionEvent().
  • If your scrollable view is attached after Activity.onCreate() (for example, waiting for a network request to finish before building your UI), call requestFocus() after attaching it.
  • If your scrollable view is initially INVISIBLE or GONE, call requestFocus() when you set it to VISIBLE.
  • If your activity contains multiple scrollable views, choose one to focus via the <requestFocus /> tag. Nested scrolling is not supported with the rotating side button.
  • If your UI contains some other view that takes focus when the user interacts with it (for example, an InputText), provide the user with some way to restore focus to the scrollable view if it loses focus. This is done by listening for taps on the scrollable view and calling requestFocus() in response.

Custom rotating behavior

If your scrollable view doesn't natively support rotary input scrolling, or if you want to use your rotary input for something other than scrolling (for example, to zoom in/out or turn dials), you can handle the scroll events yourself. Remember to make sure your view gains focus, otherwise the events will not come through.

The following code snippet shows how to use MotionEvent, InputDeviceCompat, and ViewConfigurationCompat to add custom scrolling to your view:

Kotlin

myView.setOnGenericMotionListener { v, ev ->
  if (ev.action == MotionEvent.ACTION_SCROLL &&
      ev.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)
  ) {
    // Don't forget the negation here
    val delta = -ev.getAxisValue(MotionEventCompat.AXIS_SCROLL) *
        ViewConfigurationCompat.getScaledVerticalScrollFactor(
             ViewConfiguration.get(context), context
        )
    // Swap these axes to scroll horizontally instead
    v.scrollBy(0, delta.roundToInt())
    true
  } else {
    false
  }
}

Java

myView.setOnGenericMotionListener(new View.OnGenericMotionListener() {
  @Override
  public boolean onGenericMotion(View v, MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_SCROLL &&
        ev.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)
    ) {
      // Don't forget the negation here
      float delta = -ev.getAxisValue(MotionEventCompat.AXIS_SCROLL) *
          ViewConfigurationCompat.getScaledVerticalScrollFactor(
               ViewConfiguration.get(context), context
          );

      // Swap these axes to scroll horizontally instead
      v.scrollBy(0, Math.round(delta));

      return true;
    }
    return false;
  }
});

Test using an emulator

Use the Android Emulator to simulate rotary input scrolling on a Wear device. Launch your Wear app on the emulator to run your project, or drag an APK file onto the emulator to install it.

To test the rotary input on the emulator:

  1. From the SDK manager, use the SDK tools tab to get Android Emulator 26.0.3 or higher.
  2. In Studio, select Tools > Android > AVD Manager. Create a new Wear device with API 25 or higher.
  3. Run the emulator from the Android Studio.
  4. Click the overflow button (the three dots at the bottom of the emulator toolbar). Click the Rotary input tab in the new window to open the rotary input interface and try rotary input scrolling.

The following video shows rotary input in the emulator: