3838import android .os .Build ;
3939import android .os .Build .VERSION ;
4040import android .os .Build .VERSION_CODES ;
41+ import android .os .Bundle ;
4142import android .os .Parcel ;
4243import android .os .Parcelable ;
4344import androidx .appcompat .content .res .AppCompatResources ;
6869import androidx .core .view .ViewCompat .NestedScrollType ;
6970import androidx .core .view .WindowInsetsCompat ;
7071import androidx .core .view .accessibility .AccessibilityNodeInfoCompat ;
71- import androidx .core .view .accessibility .AccessibilityNodeInfoCompat .AccessibilityActionCompat ;
72- import androidx .core .view .accessibility .AccessibilityViewCommand ;
7372import androidx .customview .view .AbsSavedState ;
7473import com .google .android .material .animation .AnimationUtils ;
7574import com .google .android .material .appbar .AppBarLayout .BaseBehavior .SavedState ;
@@ -1516,8 +1515,6 @@ public abstract static class BaseDragCallback<T extends AppBarLayout> {
15161515 @ Nullable private WeakReference <View > lastNestedScrollingChildRef ;
15171516 private BaseDragCallback onDragCallback ;
15181517
1519- private boolean coordinatorLayoutA11yScrollable ;
1520-
15211518 public BaseBehavior () {}
15221519
15231520 public BaseBehavior (Context context , AttributeSet attrs ) {
@@ -1610,7 +1607,7 @@ public void onNestedScroll(
16101607 if (dyUnconsumed == 0 ) {
16111608 // The scrolling view may scroll to the top of its content without updating the actions, so
16121609 // update here.
1613- updateAccessibilityActions (coordinatorLayout , child );
1610+ addAccessibilityDelegateIfNeeded (coordinatorLayout , child );
16141611 }
16151612 }
16161613
@@ -1870,30 +1867,12 @@ public boolean onLayoutChild(
18701867 // Make sure we dispatch the offset update
18711868 abl .onOffsetChanged (getTopAndBottomOffset ());
18721869
1873- updateAccessibilityActions (parent , abl );
1870+ addAccessibilityDelegateIfNeeded (parent , abl );
18741871 return handled ;
18751872 }
18761873
1877- private void updateAccessibilityActions (
1874+ private void addAccessibilityDelegateIfNeeded (
18781875 CoordinatorLayout coordinatorLayout , @ NonNull T appBarLayout ) {
1879- ViewCompat .removeAccessibilityAction (coordinatorLayout , ACTION_SCROLL_FORWARD .getId ());
1880- ViewCompat .removeAccessibilityAction (coordinatorLayout , ACTION_SCROLL_BACKWARD .getId ());
1881- // Don't add a11y actions if the abl has no scroll range.
1882- if (appBarLayout .getTotalScrollRange () == 0 ) {
1883- return ;
1884- }
1885- // Don't add actions if a child view doesn't have the behavior that will cause the abl to
1886- // scroll.
1887- View scrollingView = getChildWithScrollingBehavior (coordinatorLayout );
1888- if (scrollingView == null ) {
1889- return ;
1890- }
1891-
1892- // Don't add actions if the children do not have scrolling flags.
1893- if (!childrenHaveScrollFlags (appBarLayout )) {
1894- return ;
1895- }
1896-
18971876 if (!ViewCompat .hasAccessibilityDelegate (coordinatorLayout )) {
18981877 ViewCompat .setAccessibilityDelegate (
18991878 coordinatorLayout ,
@@ -1902,14 +1881,87 @@ private void updateAccessibilityActions(
19021881 public void onInitializeAccessibilityNodeInfo (
19031882 View host , @ NonNull AccessibilityNodeInfoCompat info ) {
19041883 super .onInitializeAccessibilityNodeInfo (host , info );
1905- info .setScrollable (coordinatorLayoutA11yScrollable );
19061884 info .setClassName (ScrollView .class .getName ());
1885+ if (appBarLayout .getTotalScrollRange () == 0 ) {
1886+ return ;
1887+ }
1888+ View scrollingView = getChildWithScrollingBehavior (coordinatorLayout );
1889+ // Don't add actions if a child view doesn't have the behavior that will cause the
1890+ // ABL to scroll.
1891+ if (scrollingView == null ) {
1892+ return ;
1893+ }
1894+
1895+ // Don't add actions if the children do not have scrolling flags.
1896+ if (!childrenHaveScrollFlags (appBarLayout )) {
1897+ return ;
1898+ }
1899+
1900+ if (getTopBottomOffsetForScrollingSibling ()
1901+ != -appBarLayout .getTotalScrollRange ()) {
1902+ // Add a collapsing action/forward if the view offset isn't the ABL scroll range.
1903+ // (The same offset means the view is completely collapsed).
1904+ info .addAction (ACTION_SCROLL_FORWARD );
1905+ info .setScrollable (true );
1906+ }
1907+
1908+ // Don't add an expanding action if the sibling offset is 0, which would mean the
1909+ // ABL is completely expanded.
1910+ if (getTopBottomOffsetForScrollingSibling () != 0 ) {
1911+ if (scrollingView .canScrollVertically (-1 )) {
1912+ final int dy = -appBarLayout .getDownNestedPreScrollRange ();
1913+ // Offset by non-zero.
1914+ if (dy != 0 ) {
1915+ info .addAction (ACTION_SCROLL_BACKWARD );
1916+ info .setScrollable (true );
1917+ }
1918+ } else {
1919+ info .addAction (ACTION_SCROLL_BACKWARD );
1920+ info .setScrollable (true );
1921+ }
1922+ }
1923+ }
1924+
1925+ @ Override
1926+ public boolean performAccessibilityAction (View host , int action , Bundle args ) {
1927+
1928+ if (action == AccessibilityNodeInfoCompat .ACTION_SCROLL_FORWARD ) {
1929+ appBarLayout .setExpanded (false );
1930+ return true ;
1931+ } else if (action == AccessibilityNodeInfoCompat .ACTION_SCROLL_BACKWARD ) {
1932+ if (getTopBottomOffsetForScrollingSibling () != 0 ) {
1933+ View scrollingView = getChildWithScrollingBehavior (coordinatorLayout );
1934+ if (scrollingView .canScrollVertically (-1 )) {
1935+ // Expanding action. If the view can scroll down, expand the app bar
1936+ // reflecting the logic
1937+ // in onNestedPreScroll.
1938+ final int dy = -appBarLayout .getDownNestedPreScrollRange ();
1939+ // Offset by non-zero.
1940+ if (dy != 0 ) {
1941+ onNestedPreScroll (
1942+ coordinatorLayout ,
1943+ appBarLayout ,
1944+ scrollingView ,
1945+ 0 ,
1946+ dy ,
1947+ new int [] {0 , 0 },
1948+ ViewCompat .TYPE_NON_TOUCH );
1949+ return true ;
1950+ }
1951+ } else {
1952+ // If the view can't scroll down, we are probably at the top of the
1953+ // scrolling content so expand completely.
1954+ appBarLayout .setExpanded (true );
1955+ return true ;
1956+ }
1957+ }
1958+ } else {
1959+ return super .performAccessibilityAction (host , action , args );
1960+ }
1961+ return false ;
19071962 }
19081963 });
19091964 }
1910-
1911- coordinatorLayoutA11yScrollable =
1912- addAccessibilityScrollActions (coordinatorLayout , appBarLayout , scrollingView );
19131965 }
19141966
19151967 @ Nullable
@@ -1941,74 +1993,6 @@ private boolean childrenHaveScrollFlags(AppBarLayout appBarLayout) {
19411993 return false ;
19421994 }
19431995
1944- private boolean addAccessibilityScrollActions (
1945- final CoordinatorLayout coordinatorLayout ,
1946- @ NonNull final T appBarLayout ,
1947- @ NonNull final View scrollingView ) {
1948- boolean a11yScrollable = false ;
1949- if (getTopBottomOffsetForScrollingSibling () != -appBarLayout .getTotalScrollRange ()) {
1950- // Add a collapsing action if the view offset isn't the abl scroll range.
1951- // (The same offset means the view is completely collapsed). Collapse to minimum height.
1952- addActionToExpand (coordinatorLayout , appBarLayout , ACTION_SCROLL_FORWARD , false );
1953- a11yScrollable = true ;
1954- }
1955- // Don't add an expanding action if the sibling offset is 0, which would mean the abl is
1956- // completely expanded.
1957- if (getTopBottomOffsetForScrollingSibling () != 0 ) {
1958- if (scrollingView .canScrollVertically (-1 )) {
1959- // Expanding action. If the view can scroll down, expand the app bar reflecting the logic
1960- // in onNestedPreScroll.
1961- final int dy = -appBarLayout .getDownNestedPreScrollRange ();
1962- // Offset by non-zero.
1963- if (dy != 0 ) {
1964- ViewCompat .replaceAccessibilityAction (
1965- coordinatorLayout ,
1966- ACTION_SCROLL_BACKWARD ,
1967- null ,
1968- new AccessibilityViewCommand () {
1969- @ Override
1970- public boolean perform (@ NonNull View view , @ Nullable CommandArguments arguments ) {
1971- onNestedPreScroll (
1972- coordinatorLayout ,
1973- appBarLayout ,
1974- scrollingView ,
1975- 0 ,
1976- dy ,
1977- new int [] {0 , 0 },
1978- ViewCompat .TYPE_NON_TOUCH );
1979- return true ;
1980- }
1981- });
1982- a11yScrollable = true ;
1983- }
1984- } else {
1985- // If the view can't scroll down, we are probably at the top of the scrolling content so
1986- // expand completely.
1987- addActionToExpand (coordinatorLayout , appBarLayout , ACTION_SCROLL_BACKWARD , true );
1988- a11yScrollable = true ;
1989- }
1990- }
1991- return a11yScrollable ;
1992- }
1993-
1994- private void addActionToExpand (
1995- CoordinatorLayout parent ,
1996- @ NonNull final T appBarLayout ,
1997- @ NonNull AccessibilityActionCompat action ,
1998- final boolean expand ) {
1999- ViewCompat .replaceAccessibilityAction (
2000- parent ,
2001- action ,
2002- null ,
2003- new AccessibilityViewCommand () {
2004- @ Override
2005- public boolean perform (@ NonNull View view , @ Nullable CommandArguments arguments ) {
2006- appBarLayout .setExpanded (expand );
2007- return true ;
2008- }
2009- });
2010- }
2011-
20121996 @ Override
20131997 boolean canDragView (T view ) {
20141998 if (onDragCallback != null ) {
@@ -2112,7 +2096,7 @@ int setHeaderTopBottomOffset(
21122096 offsetDelta = 0 ;
21132097 }
21142098
2115- updateAccessibilityActions (coordinatorLayout , appBarLayout );
2099+ addAccessibilityDelegateIfNeeded (coordinatorLayout , appBarLayout );
21162100 return consumed ;
21172101 }
21182102
@@ -2410,8 +2394,6 @@ public boolean onDependentViewChanged(
24102394 public void onDependentViewRemoved (
24112395 @ NonNull CoordinatorLayout parent , @ NonNull View child , @ NonNull View dependency ) {
24122396 if (dependency instanceof AppBarLayout ) {
2413- ViewCompat .removeAccessibilityAction (parent , ACTION_SCROLL_FORWARD .getId ());
2414- ViewCompat .removeAccessibilityAction (parent , ACTION_SCROLL_BACKWARD .getId ());
24152397 ViewCompat .setAccessibilityDelegate (parent , null );
24162398 }
24172399 }
0 commit comments