1 /*
2  * Copyright (C) 2016 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 com.android.settings.widget;
18 
19 import android.content.Context;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 import android.text.TextUtils;
23 import android.util.AttributeSet;
24 import android.view.View;
25 
26 import androidx.viewpager.widget.ViewPager;
27 
28 import java.util.Locale;
29 
30 /**
31  * A {@link ViewPager} that's aware of RTL changes when used with FragmentPagerAdapter.
32  */
33 public final class RtlCompatibleViewPager extends ViewPager {
34 
35     /**
36      * Callback interface for responding to changing state of the selected page.
37      * Positions supplied will always be the logical position in the adapter -
38      * that is, the 0 index corresponds to the left-most page in LTR and the
39      * right-most page in RTL.
40      */
41 
RtlCompatibleViewPager(Context context)42     public RtlCompatibleViewPager(Context context) {
43         this(context, null /* attrs */);
44     }
45 
RtlCompatibleViewPager(Context context, AttributeSet attrs)46     public RtlCompatibleViewPager(Context context, AttributeSet attrs) {
47         super(context, attrs);
48     }
49 
50     @Override
getCurrentItem()51     public int getCurrentItem() {
52         return getRtlAwareIndex(super.getCurrentItem());
53     }
54 
55     @Override
setCurrentItem(int item)56     public void setCurrentItem(int item) {
57         super.setCurrentItem(getRtlAwareIndex(item));
58     }
59 
60     @Override
onSaveInstanceState()61     public Parcelable onSaveInstanceState() {
62         Parcelable parcelable = super.onSaveInstanceState();
63 
64         RtlSavedState rtlSavedState = new RtlSavedState(parcelable);
65         rtlSavedState.position = getCurrentItem();
66         return rtlSavedState;
67     }
68 
69     @Override
onRestoreInstanceState(Parcelable state)70     public void onRestoreInstanceState(Parcelable state) {
71         RtlSavedState rtlSavedState = (RtlSavedState) state;
72         super.onRestoreInstanceState(rtlSavedState.getSuperState());
73 
74         setCurrentItem(rtlSavedState.position);
75     }
76 
77     /**
78      * Get a "RTL friendly" index. If the locale is LTR, the index is returned as is.
79      * Otherwise it's transformed so view pager can render views using the new index for RTL. For
80      * example, the second view will be rendered to the left of first view.
81      *
82      * @param index The logical index.
83      */
getRtlAwareIndex(int index)84     public int getRtlAwareIndex(int index) {
85         // Using TextUtils rather than View.getLayoutDirection() because LayoutDirection is not
86         // defined until onMeasure, and this is called before then.
87         if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
88                 == View.LAYOUT_DIRECTION_RTL) {
89             return getAdapter().getCount() - index - 1;
90         }
91         return index;
92     }
93 
94     static class RtlSavedState extends BaseSavedState {
95         int position;
96 
RtlSavedState(Parcelable superState)97         public RtlSavedState(Parcelable superState) {
98             super(superState);
99         }
100 
RtlSavedState(Parcel in, ClassLoader loader)101         private RtlSavedState(Parcel in, ClassLoader loader) {
102             super(in, loader);
103             position = in.readInt();
104         }
105 
106         @Override
writeToParcel(Parcel out, int flags)107         public void writeToParcel(Parcel out, int flags) {
108             super.writeToParcel(out, flags);
109             out.writeInt(position);
110         }
111 
112         public static final Parcelable.ClassLoaderCreator<RtlSavedState> CREATOR
113                 = new Parcelable.ClassLoaderCreator<RtlSavedState>() {
114             @Override
115             public RtlSavedState createFromParcel(Parcel source,
116                     ClassLoader loader) {
117                 return new RtlSavedState(source, loader);
118             }
119 
120             @Override
121             public RtlSavedState createFromParcel(Parcel in) {
122                 return new RtlSavedState(in, null);
123             }
124 
125             @Override
126             public RtlSavedState[] newArray(int size) {
127                 return new RtlSavedState[size];
128             }
129         };
130 
131     }
132 
133 }
134