1 /*
2  * Copyright (C) 2022 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.accessibility;
18 
19 import android.content.Context;
20 import android.util.AttributeSet;
21 import android.view.View;
22 import android.widget.FrameLayout;
23 import android.widget.LinearLayout;
24 
25 import androidx.preference.Preference;
26 import androidx.preference.PreferenceViewHolder;
27 import androidx.viewpager.widget.ViewPager;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.util.Preconditions;
31 import com.android.settings.R;
32 import com.android.settings.display.PreviewPagerAdapter;
33 import com.android.settings.widget.DotsPageIndicator;
34 
35 /**
36  * A {@link Preference} that could show the preview related to the text and reading options.
37  */
38 public class TextReadingPreviewPreference extends Preference {
39     private int mCurrentItem;
40     private int mLastLayerIndex;
41     private PreviewPagerAdapter mPreviewAdapter;
42 
43     private int mLayoutMinHorizontalPadding = 0;
44     private int mBackgroundMinHorizontalPadding = 0;
45 
46     private final ViewPager.OnPageChangeListener mPageChangeListener =
47             new ViewPager.OnPageChangeListener() {
48         @Override
49         public void onPageScrolled(int i, float v, int i1) {
50             // Do nothing
51         }
52 
53         @Override
54         public void onPageSelected(int i) {
55             mCurrentItem = i;
56         }
57 
58         @Override
59         public void onPageScrollStateChanged(int i) {
60             // Do nothing
61         }
62     };
63 
TextReadingPreviewPreference(Context context)64     TextReadingPreviewPreference(Context context) {
65         super(context);
66         init();
67     }
68 
TextReadingPreviewPreference(Context context, AttributeSet attrs)69     public TextReadingPreviewPreference(Context context, AttributeSet attrs) {
70         super(context, attrs);
71         init();
72     }
73 
TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr)74     TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr) {
75         super(context, attrs, defStyleAttr);
76         init();
77     }
78 
TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)79     TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr,
80             int defStyleRes) {
81         super(context, attrs, defStyleAttr, defStyleRes);
82         init();
83     }
84 
85     @Override
onBindViewHolder(PreferenceViewHolder holder)86     public void onBindViewHolder(PreferenceViewHolder holder) {
87         super.onBindViewHolder(holder);
88 
89         FrameLayout previewLayout = (FrameLayout) holder.itemView;
90         LinearLayout backgroundView = previewLayout.findViewById(R.id.preview_background);
91         adjustPaddings(previewLayout, backgroundView);
92 
93         final ViewPager viewPager = (ViewPager) holder.findViewById(R.id.preview_pager);
94         viewPager.addOnPageChangeListener(mPageChangeListener);
95         final DotsPageIndicator pageIndicator =
96                 (DotsPageIndicator) holder.findViewById(R.id.page_indicator);
97         updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter);
98         updatePagerAndIndicator(viewPager, pageIndicator);
99     }
100 
101     /**
102      * Set the minimum preview layout horizontal inner padding.
103      */
setLayoutMinHorizontalPadding(int layoutMinHorizontalPadding)104     void setLayoutMinHorizontalPadding(int layoutMinHorizontalPadding) {
105         mLayoutMinHorizontalPadding = layoutMinHorizontalPadding;
106     }
107 
108     /**
109      * Set the minimum preview background view horizontal inner padding.
110      */
setBackgroundMinHorizontalPadding(int backgroundMinHorizontalPadding)111     void setBackgroundMinHorizontalPadding(int backgroundMinHorizontalPadding) {
112         mBackgroundMinHorizontalPadding = backgroundMinHorizontalPadding;
113     }
114 
115     @VisibleForTesting
adjustPaddings(FrameLayout previewLayout, LinearLayout backgroundView)116     void adjustPaddings(FrameLayout previewLayout, LinearLayout backgroundView) {
117         previewLayout.setPadding(
118                 Math.max(previewLayout.getPaddingStart(), mLayoutMinHorizontalPadding),
119                 previewLayout.getPaddingTop(),
120                 Math.max(previewLayout.getPaddingEnd(), mLayoutMinHorizontalPadding),
121                 previewLayout.getPaddingBottom()
122         );
123         backgroundView.setPadding(
124                 Math.max(backgroundView.getPaddingStart(), mBackgroundMinHorizontalPadding),
125                 backgroundView.getPaddingTop(),
126                 Math.max(backgroundView.getPaddingEnd(), mBackgroundMinHorizontalPadding),
127                 backgroundView.getPaddingBottom()
128         );
129     }
130 
setPreviewAdapter(PreviewPagerAdapter previewAdapter)131     void setPreviewAdapter(PreviewPagerAdapter previewAdapter) {
132         if (previewAdapter != mPreviewAdapter) {
133             mPreviewAdapter = previewAdapter;
134             notifyChanged();
135         }
136     }
137 
setCurrentItem(int currentItem)138     void setCurrentItem(int currentItem) {
139         Preconditions.checkNotNull(mPreviewAdapter,
140                 "Preview adapter is null, you should init the preview adapter first");
141 
142         if (currentItem != mCurrentItem) {
143             mCurrentItem = currentItem;
144             notifyChanged();
145         }
146     }
147 
setLastLayerIndex(int lastLayerIndex)148     void setLastLayerIndex(int lastLayerIndex) {
149         mLastLayerIndex = lastLayerIndex;
150     }
151 
getCurrentItem()152     int getCurrentItem() {
153         return mCurrentItem;
154     }
155 
updateAdapterIfNeeded(ViewPager viewPager, DotsPageIndicator pageIndicator, PreviewPagerAdapter previewAdapter)156     private void updateAdapterIfNeeded(ViewPager viewPager, DotsPageIndicator pageIndicator,
157             PreviewPagerAdapter previewAdapter) {
158         if (viewPager.getAdapter() == previewAdapter) {
159             return;
160         }
161 
162         viewPager.setAdapter(previewAdapter);
163 
164         if (previewAdapter != null) {
165             pageIndicator.setViewPager(viewPager);
166         } else {
167             mCurrentItem = 0;
168         }
169     }
170 
updatePagerAndIndicator(ViewPager viewPager, DotsPageIndicator pageIndicator)171     private void updatePagerAndIndicator(ViewPager viewPager, DotsPageIndicator pageIndicator) {
172         if (viewPager.getAdapter() == null) {
173             return;
174         }
175 
176         if (viewPager.getCurrentItem() != mCurrentItem) {
177             viewPager.setCurrentItem(mCurrentItem);
178         }
179 
180         pageIndicator.setVisibility(
181                 viewPager.getAdapter().getCount() > 1 ? View.VISIBLE : View.GONE);
182     }
183 
init()184     private void init() {
185         // set up the minimum horizontal paddings
186         setLayoutMinHorizontalPadding(getContext().getResources().getDimensionPixelSize(
187                 R.dimen.text_reading_preview_layout_padding_horizontal_min));
188         setBackgroundMinHorizontalPadding(getContext().getResources().getDimensionPixelSize(
189                 R.dimen.text_reading_preview_background_padding_horizontal_min));
190 
191         setLayoutResource(R.layout.accessibility_text_reading_preview);
192     }
193 
notifyPreviewPagerChanged(int pagerIndex)194     void notifyPreviewPagerChanged(int pagerIndex) {
195         Preconditions.checkNotNull(mPreviewAdapter,
196                 "Preview adapter is null, you should init the preview adapter first");
197 
198         if (pagerIndex != mLastLayerIndex) {
199             mPreviewAdapter.setPreviewLayer(pagerIndex, mLastLayerIndex, getCurrentItem(),
200                     /* animate= */ false);
201         }
202 
203         mLastLayerIndex = pagerIndex;
204     }
205 }
206