1919import com .google .android .material .test .R ;
2020
2121import static android .content .Context .ACCESSIBILITY_SERVICE ;
22+ import static androidx .core .view .accessibility .AccessibilityNodeInfoCompat .AccessibilityActionCompat .ACTION_COLLAPSE ;
23+ import static androidx .core .view .accessibility .AccessibilityNodeInfoCompat .AccessibilityActionCompat .ACTION_DISMISS ;
24+ import static androidx .core .view .accessibility .AccessibilityNodeInfoCompat .AccessibilityActionCompat .ACTION_EXPAND ;
25+ import static com .google .android .material .bottomsheet .BottomSheetBehavior .VIEW_INDEX_ACCESSIBILITY_DELEGATE_VIEW ;
2226import static com .google .common .truth .Truth .assertThat ;
2327import static org .robolectric .Shadows .shadowOf ;
2428
3236import androidx .annotation .Nullable ;
3337import androidx .coordinatorlayout .widget .CoordinatorLayout ;
3438import androidx .core .view .ViewCompat ;
39+ import androidx .core .view .accessibility .AccessibilityNodeInfoCompat .AccessibilityActionCompat ;
3540import androidx .test .core .app .ApplicationProvider ;
3641import androidx .test .platform .app .InstrumentationRegistry ;
42+ import java .util .ArrayList ;
3743import org .junit .Before ;
3844import org .junit .Test ;
3945import org .junit .runner .RunWith ;
@@ -195,6 +201,140 @@ public void test_halfExpandedBottomSheetMoveToCollapsed_whenPreviouslyExpanded()
195201 .isEqualTo (BottomSheetBehavior .STATE_COLLAPSED );
196202 }
197203
204+ @ Test
205+ public void test_customActionExpand () {
206+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_COLLAPSED );
207+ activity .addViewToBottomSheet (dragHandleView );
208+ shadowOf (accessibilityManager ).setEnabled (true );
209+
210+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
211+
212+ ViewCompat .performAccessibilityAction (dragHandleView , ACTION_EXPAND .getId (), /* args= */ null );
213+
214+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
215+
216+ assertThat (activity .bottomSheetBehavior .getState ())
217+ .isEqualTo (BottomSheetBehavior .STATE_EXPANDED );
218+ }
219+
220+ @ Test
221+ public void test_customActionHalfExpand () {
222+ activity .bottomSheetBehavior .setFitToContents (false );
223+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_COLLAPSED );
224+ activity .addViewToBottomSheet (dragHandleView );
225+ shadowOf (accessibilityManager ).setEnabled (true );
226+
227+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
228+
229+ ViewCompat .performAccessibilityAction (
230+ dragHandleView , getHalfExpandActionId (), /* args= */ null );
231+
232+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
233+
234+ assertThat (activity .bottomSheetBehavior .getState ())
235+ .isEqualTo (BottomSheetBehavior .STATE_HALF_EXPANDED );
236+ }
237+
238+ @ Test
239+ public void test_customActionCollapse () {
240+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_EXPANDED );
241+ activity .addViewToBottomSheet (dragHandleView );
242+ shadowOf (accessibilityManager ).setEnabled (true );
243+
244+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
245+
246+ ViewCompat .performAccessibilityAction (
247+ dragHandleView , ACTION_COLLAPSE .getId (), /* args= */ null );
248+
249+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
250+
251+ assertThat (activity .bottomSheetBehavior .getState ())
252+ .isEqualTo (BottomSheetBehavior .STATE_COLLAPSED );
253+ }
254+
255+ @ Test
256+ public void test_customActionDismiss () {
257+ activity .bottomSheetBehavior .setHideable (true );
258+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_EXPANDED );
259+ activity .addViewToBottomSheet (dragHandleView );
260+ shadowOf (accessibilityManager ).setEnabled (true );
261+
262+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
263+
264+ ViewCompat .performAccessibilityAction (dragHandleView , ACTION_DISMISS .getId (), /* args= */ null );
265+
266+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
267+
268+ assertThat (activity .bottomSheetBehavior .getState ()).isEqualTo (BottomSheetBehavior .STATE_HIDDEN );
269+ }
270+
271+ @ Test
272+ public void test_customActionSetInCollapsedStateWhenHalfExpandableAndHideable () {
273+ activity .bottomSheetBehavior .setFitToContents (false );
274+ activity .bottomSheetBehavior .setHideable (true );
275+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_COLLAPSED );
276+ activity .addViewToBottomSheet (dragHandleView );
277+ shadowOf (accessibilityManager ).setEnabled (true );
278+
279+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
280+
281+ assertThat (hasAccessibilityAction (dragHandleView , getHalfExpandActionId ())).isTrue ();
282+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_EXPAND .getId ())).isTrue ();
283+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_DISMISS .getId ())).isTrue ();
284+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_COLLAPSE .getId ())).isFalse ();
285+ }
286+
287+ @ Test
288+ public void test_customActionSetInExpandedStateWhenHalfExpandableAndNotHideable () {
289+ activity .bottomSheetBehavior .setHideable (false );
290+ activity .bottomSheetBehavior .setFitToContents (false );
291+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_EXPANDED );
292+ activity .addViewToBottomSheet (dragHandleView );
293+ shadowOf (accessibilityManager ).setEnabled (true );
294+
295+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
296+
297+ assertThat (hasAccessibilityAction (dragHandleView , getHalfExpandActionId ())).isTrue ();
298+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_EXPAND .getId ())).isFalse ();
299+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_DISMISS .getId ())).isFalse ();
300+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_COLLAPSE .getId ())).isTrue ();
301+ }
302+
303+ @ Test
304+ public void test_customActionSetInCollapsedStateWhenNotHideable () {
305+ activity .bottomSheetBehavior .setHideable (false );
306+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_COLLAPSED );
307+ activity .addViewToBottomSheet (dragHandleView );
308+ shadowOf (accessibilityManager ).setEnabled (true );
309+
310+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
311+
312+ assertThat (getHalfExpandActionId ()).isEqualTo (View .NO_ID );
313+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_EXPAND .getId ())).isTrue ();
314+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_DISMISS .getId ())).isFalse ();
315+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_COLLAPSE .getId ())).isFalse ();
316+ }
317+
318+ @ Test
319+ public void test_customActionSetInExpandedStateWhenHideable () {
320+ activity .bottomSheetBehavior .setHideable (true );
321+ activity .bottomSheetBehavior .setState (BottomSheetBehavior .STATE_EXPANDED );
322+ activity .addViewToBottomSheet (dragHandleView );
323+ shadowOf (accessibilityManager ).setEnabled (true );
324+
325+ InstrumentationRegistry .getInstrumentation ().waitForIdleSync ();
326+
327+ assertThat (getHalfExpandActionId ()).isEqualTo (View .NO_ID );
328+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_EXPAND .getId ())).isFalse ();
329+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_DISMISS .getId ())).isTrue ();
330+ assertThat (hasAccessibilityAction (dragHandleView , ACTION_COLLAPSE .getId ())).isTrue ();
331+ }
332+
333+ private int getHalfExpandActionId () {
334+ return activity .bottomSheetBehavior .expandHalfwayActionIds .get (
335+ VIEW_INDEX_ACCESSIBILITY_DELEGATE_VIEW , View .NO_ID );
336+ }
337+
198338 private void assertImportantForAccessibility (boolean important ) {
199339 if (important ) {
200340 assertThat (ViewCompat .getImportantForAccessibility (dragHandleView ))
@@ -205,6 +345,21 @@ private void assertImportantForAccessibility(boolean important) {
205345 }
206346 }
207347
348+ // TODO(b/250622249): remove duplicated methods after sharing test util classes
349+ private static boolean hasAccessibilityAction (View view , int actionId ) {
350+ return getAccessibilityActionList (view ).stream ().anyMatch (action -> action .getId () == actionId );
351+ }
352+
353+ private static ArrayList <AccessibilityActionCompat > getAccessibilityActionList (View view ) {
354+ @ SuppressWarnings ({"unchecked" })
355+ ArrayList <AccessibilityActionCompat > actions =
356+ (ArrayList <AccessibilityActionCompat >) view .getTag (R .id .tag_accessibility_actions );
357+ if (actions == null ) {
358+ actions = new ArrayList <>();
359+ }
360+ return actions ;
361+ }
362+
208363 private static class TestActivity extends AppCompatActivity {
209364 @ Nullable
210365 private CoordinatorLayout container ;
0 commit comments