Add RTL support for A11yMenu ViewPager.
When in RTL languages, reverses the direction of the left & right buttons.
Demonstration video: https://x20web.corp.google.com/users/jo/jonesriley/fabFootage/viewPager2.mp4
Bug: 279191187
Flag: EXEMPT internal refactoring
Test: atest A11yMenuServiceTests
Change-Id: I9626f504a444928d717f3f9b03600d7058203c78
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/Android.bp
index c881e07..c60eb61 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/Android.bp
+++ b/packages/SystemUI/accessibility/accessibilitymenu/Android.bp
@@ -36,7 +36,7 @@
"androidx.coordinatorlayout_coordinatorlayout",
"androidx.core_core",
"androidx.preference_preference",
- "androidx.viewpager_viewpager",
+ "androidx.viewpager2_viewpager2",
"com_android_systemui_flags_lib",
"SettingsLibDisplayUtils",
"SettingsLibSettingsTheme",
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/footerlayout_switch_page.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/footerlayout_switch_page.xml
index 462c90b..e1b6e63 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/footerlayout_switch_page.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/footerlayout_switch_page.xml
@@ -22,7 +22,7 @@
android:orientation="horizontal">
<ImageButton
- android:id="@+id/menu_prev_button"
+ android:id="@+id/menu_left_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -38,7 +38,7 @@
android:background="?android:attr/listDivider"/>
<ImageButton
- android:id="@+id/menu_next_button"
+ android:id="@+id/menu_right_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_view.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_view.xml
index c198443..c0aa1b3 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_view.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_view.xml
@@ -2,7 +2,7 @@
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:horizontalSpacing="@dimen/a11ymenu_grid_layout_margin"
android:listSelector="@android:color/transparent"
android:numColumns="3"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
index 28a633e..6be7655 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
@@ -6,18 +6,16 @@
android:background="@drawable/view_background"
>
<LinearLayout
- android:layout_width="@dimen/row_width"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
- <androidx.viewpager.widget.ViewPager
+ <androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/table_margin_top"
android:paddingBottom="@dimen/a11ymenu_layout_margin"
- android:paddingLeft="@dimen/a11ymenu_layout_margin"
- android:paddingRight="@dimen/a11ymenu_layout_margin"
android:layout_gravity="center"
android:gravity="center"
/>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
index 20c63df..78fbf01 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
@@ -16,7 +16,11 @@
package com.android.systemui.accessibility.accessibilitymenu.view;
+import static android.view.View.LAYOUT_DIRECTION_LTR;
+
+import android.content.res.Configuration;
import android.graphics.Rect;
+import android.text.TextUtils;
import android.view.TouchDelegate;
import android.view.View;
import android.view.View.OnClickListener;
@@ -37,46 +41,61 @@
public interface A11yMenuFooterCallBack {
/** Calls back when user clicks the left button. */
- void onLeftButtonClicked();
+ void onNextButtonClicked();
/** Calls back when user clicks the right button. */
- void onRightButtonClicked();
+ void onPreviousButtonClicked();
}
private final FooterButtonClickListener mFooterButtonClickListener;
- private ImageButton mPreviousPageBtn;
- private ImageButton mNextPageBtn;
+ private ImageButton mPageLeftBtn;
+ private ImageButton mPageRightBtn;
private View mTopListDivider;
private View mBottomListDivider;
private final A11yMenuFooterCallBack mCallBack;
+ private final ViewGroup mMenuLayout;
+ private int mRightToLeftDirection = LAYOUT_DIRECTION_LTR;
public A11yMenuFooter(ViewGroup menuLayout, A11yMenuFooterCallBack callBack) {
this.mCallBack = callBack;
mFooterButtonClickListener = new FooterButtonClickListener();
configureFooterLayout(menuLayout);
+ mMenuLayout = menuLayout;
}
public @Nullable ImageButton getPreviousPageBtn() {
- return mPreviousPageBtn;
+ return mRightToLeftDirection == LAYOUT_DIRECTION_LTR
+ ? mPageLeftBtn : mPageRightBtn;
}
public @Nullable ImageButton getNextPageBtn() {
- return mNextPageBtn;
+ return mRightToLeftDirection == LAYOUT_DIRECTION_LTR
+ ? mPageRightBtn : mPageLeftBtn;
+ }
+
+ /** Sets right to left direction of footer. */
+ public void updateRightToLeftDirection(Configuration configuration) {
+ mRightToLeftDirection = TextUtils.getLayoutDirectionFromLocale(
+ configuration.getLocales().get(0));
+ getPreviousPageBtn().setContentDescription(mMenuLayout.getResources().getString(
+ R.string.previous_button_content_description));
+ getNextPageBtn().setContentDescription(mMenuLayout.getResources().getString(
+ R.string.next_button_content_description));
}
private void configureFooterLayout(ViewGroup menuLayout) {
ViewGroup footerContainer = menuLayout.findViewById(R.id.footerlayout);
footerContainer.setVisibility(View.VISIBLE);
- mPreviousPageBtn = menuLayout.findViewById(R.id.menu_prev_button);
- mNextPageBtn = menuLayout.findViewById(R.id.menu_next_button);
+ mPageLeftBtn = menuLayout.findViewById(R.id.menu_left_button);
+ mPageRightBtn = menuLayout.findViewById(R.id.menu_right_button);
mTopListDivider = menuLayout.findViewById(R.id.top_listDivider);
mBottomListDivider = menuLayout.findViewById(R.id.bottom_listDivider);
// Registers listeners for footer buttons.
- setListener(mPreviousPageBtn);
- setListener(mNextPageBtn);
+ setListener(mPageLeftBtn);
+ setListener(mPageRightBtn);
menuLayout
.getViewTreeObserver()
@@ -85,8 +104,8 @@
@Override
public void onGlobalLayout() {
menuLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- expandBtnTouchArea(mPreviousPageBtn, menuLayout);
- expandBtnTouchArea(mNextPageBtn, (View) mNextPageBtn.getParent());
+ expandBtnTouchArea(mPageLeftBtn, menuLayout);
+ expandBtnTouchArea(mPageRightBtn, (View) mPageRightBtn.getParent());
}
});
}
@@ -115,10 +134,10 @@
private class FooterButtonClickListener implements OnClickListener {
@Override
public void onClick(View view) {
- if (view.getId() == R.id.menu_prev_button) {
- mCallBack.onLeftButtonClicked();
- } else if (view.getId() == R.id.menu_next_button) {
- mCallBack.onRightButtonClicked();
+ if (view.getId() == getPreviousPageBtn().getId()) {
+ mCallBack.onPreviousButtonClicked();
+ } else if (view.getId() == getNextPageBtn().getId()) {
+ mCallBack.onNextButtonClicked();
}
}
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
index 6bea30f..de3c472 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -145,13 +145,14 @@
final Display display = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
final Context context = mService.createDisplayContext(display).createWindowContext(
TYPE_ACCESSIBILITY_OVERLAY, null);
- mLayout = new FrameLayout(context);
+ mLayout = new A11yMenuFrameLayout(context);
updateLayoutPosition();
inflateLayoutAndSetOnTouchListener(mLayout, context);
mA11yMenuViewPager = new A11yMenuViewPager(mService, context);
mA11yMenuViewPager.configureViewPagerAndFooter(mLayout, createShortcutList(), pageIndex);
mWindowManager.addView(mLayout, mLayoutParameter);
mLayout.setVisibility(lastVisibilityState);
+ mA11yMenuViewPager.updateFooterState();
return mLayout;
}
@@ -393,4 +394,16 @@
}
}), timeoutDurationMs);
}
+
+ private class A11yMenuFrameLayout extends FrameLayout {
+ A11yMenuFrameLayout(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ public void dispatchConfigurationChanged(Configuration newConfig) {
+ super.dispatchConfigurationChanged(newConfig);
+ mA11yMenuViewPager.mA11yMenuFooter.updateRightToLeftDirection(newConfig);
+ }
+ }
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
index b969017..08bbf19 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
@@ -20,7 +20,6 @@
import android.content.res.Configuration;
import android.graphics.Insets;
import android.util.DisplayMetrics;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -29,7 +28,7 @@
import android.view.WindowMetrics;
import android.widget.GridView;
-import androidx.viewpager.widget.ViewPager;
+import androidx.viewpager2.widget.ViewPager2;
import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
import com.android.systemui.accessibility.accessibilitymenu.R;
@@ -133,9 +132,9 @@
* The pager widget, which handles animation and allows swiping horizontally to access previous
* and next gridView pages.
*/
- protected ViewPager mViewPager;
+ protected ViewPager2 mViewPager;
- private ViewPagerAdapter<GridView> mViewPagerAdapter;
+ private ViewPagerAdapter mViewPagerAdapter;
private final List<GridView> mGridPageList = new ArrayList<>();
/** The footer, which provides buttons to switch between pages */
@@ -169,6 +168,8 @@
initViewPager();
initChildPage();
mA11yMenuFooter = new A11yMenuFooter(a11yMenuLayout, mFooterCallbacks);
+ mA11yMenuFooter.updateRightToLeftDirection(
+ a11yMenuLayout.getResources().getConfiguration());
updateFooterState();
registerOnGlobalLayoutListener();
goToPage(pageIndex);
@@ -177,18 +178,12 @@
/** Initializes viewPager and its adapter. */
private void initViewPager() {
mViewPager = mA11yMenuLayout.findViewById(R.id.view_pager);
- mViewPagerAdapter = new ViewPagerAdapter<>();
+ mViewPagerAdapter = new ViewPagerAdapter(mService);
+ mViewPager.setOffscreenPageLimit(2);
mViewPager.setAdapter(mViewPagerAdapter);
mViewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
- mViewPager.addOnPageChangeListener(
- new ViewPager.OnPageChangeListener() {
- @Override
- public void onPageScrollStateChanged(int state) {}
-
- @Override
- public void onPageScrolled(
- int position, float positionOffset, int positionOffsetPixels) {}
-
+ mViewPager.registerOnPageChangeCallback(
+ new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
updateFooterState();
@@ -206,31 +201,14 @@
mGridPageList.clear();
}
- // Generate pages by calculating # of items per grid.
- for (List<A11yMenuShortcut> page : GridViewParams.generateShortcutSubLists(
- GridViewParams.getGridItemCount(mService), mA11yMenuShortcutList)
- ) {
- addGridPage(page);
- }
-
- mViewPagerAdapter.set(mGridPageList);
- }
-
- private void addGridPage(List<A11yMenuShortcut> shortcutDataListInPage) {
- LayoutInflater inflater = LayoutInflater.from(mDisplayContext);
- View view = inflater.inflate(R.layout.grid_view, null);
- GridView gridView = view.findViewById(R.id.gridview);
- A11yMenuAdapter adapter = new A11yMenuAdapter(
- mService, mDisplayContext, shortcutDataListInPage);
- gridView.setNumColumns(GridViewParams.getGridColumnCount(mService));
- gridView.setAdapter(adapter);
- mGridPageList.add(gridView);
+ mViewPagerAdapter.set(GridViewParams.generateShortcutSubLists(
+ GridViewParams.getGridItemCount(mService), mA11yMenuShortcutList));
}
/** Updates footer's state by index of current page in view pager. */
- private void updateFooterState() {
+ public void updateFooterState() {
int currentPage = mViewPager.getCurrentItem();
- int lastPage = mViewPager.getAdapter().getCount() - 1;
+ int lastPage = mViewPager.getAdapter().getItemCount() - 1;
mA11yMenuFooter.getPreviousPageBtn().setEnabled(currentPage > 0);
mA11yMenuFooter.getNextPageBtn().setEnabled(currentPage < lastPage);
}
@@ -239,7 +217,7 @@
if (mViewPager == null) {
return;
}
- if ((pageIndex >= 0) && (pageIndex < mViewPager.getAdapter().getCount())) {
+ if ((pageIndex >= 0) && (pageIndex < mViewPager.getAdapter().getItemCount())) {
mViewPager.setCurrentItem(pageIndex);
}
}
@@ -341,7 +319,7 @@
protected A11yMenuFooterCallBack mFooterCallbacks =
new A11yMenuFooterCallBack() {
@Override
- public void onLeftButtonClicked() {
+ public void onPreviousButtonClicked() {
// Moves to previous page.
int targetPage = mViewPager.getCurrentItem() - 1;
goToPage(targetPage);
@@ -349,7 +327,7 @@
}
@Override
- public void onRightButtonClicked() {
+ public void onNextButtonClicked() {
// Moves to next page.
int targetPage = mViewPager.getCurrentItem() + 1;
goToPage(targetPage);
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
index 5670d72..43ec956 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
@@ -16,55 +16,64 @@
package com.android.systemui.accessibility.accessibilitymenu.view;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.GridView;
-import androidx.viewpager.widget.PagerAdapter;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
+import com.android.systemui.accessibility.accessibilitymenu.R;
+import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut;
import java.util.List;
/** The pager adapter, which provides the pages to the view pager widget. */
-class ViewPagerAdapter<T extends View> extends PagerAdapter {
+class ViewPagerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
- /** The widget list in each page of view pager. */
- private List<T> mWidgetList;
+ /** List of shortcuts, split into sub lists per page */
+ private List<List<A11yMenuShortcut>> mShortcutList;
+ private final AccessibilityMenuService mService;
- ViewPagerAdapter() {}
+ ViewPagerAdapter(AccessibilityMenuService service) {
+ mService = service;
+ }
- public void set(List<T> tList) {
- mWidgetList = tList;
+ public void set(List<List<A11yMenuShortcut>> tList) {
+ mShortcutList = tList;
notifyDataSetChanged();
}
+ @NonNull
@Override
- public int getCount() {
- if (mWidgetList == null) {
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ View view = inflater.inflate(R.layout.grid_view, parent, false);
+ return new MenuViewHolder(view.findViewById(R.id.gridview));
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ A11yMenuAdapter adapter = new A11yMenuAdapter(
+ mService, holder.itemView.getContext(), mShortcutList.get(position));
+ GridView gridView = (GridView) holder.itemView;
+ gridView.setNumColumns(A11yMenuViewPager.GridViewParams.getGridColumnCount(mService));
+ gridView.setAdapter(adapter);
+ }
+
+ @Override
+ public int getItemCount() {
+ if (mShortcutList == null) {
return 0;
}
- return mWidgetList.size();
+ return mShortcutList.size();
}
- @Override
- public int getItemPosition(Object object) {
- return POSITION_NONE;
- }
-
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return view == object;
- }
-
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- if (mWidgetList == null) {
- return null;
+ static class MenuViewHolder extends RecyclerView.ViewHolder {
+ MenuViewHolder(View itemView) {
+ super(itemView);
}
- container.addView(mWidgetList.get(position));
- return mWidgetList.get(position);
}
-
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView((View) object);
- }
-}
+}
\ No newline at end of file